diff --git a/.eslintrc.js b/.eslintrc.js index 4b9d86e4be3..6e70df2ff27 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -38,6 +38,28 @@ module.exports = { 'no-case-declarations': 'warn', 'prefer-regex-literals': 'warn', 'react/prop-types': 'warn', + + // Enforce notification hooks + 'no-restricted-imports': [ + 'error', + { + paths: [ + { + name: '@opentrons/react-api-client', + importNames: [ + 'useAllRunsQuery', + 'useRunQuery', + 'useLastRunCommandKey', + 'useCurrentMaintenanceRun', + 'useDeckConfigurationQuery', + 'useAllCommandsAsPreSerializedList', + ], + message: + 'The HTTP hook is deprecated. Utilize the equivalent notification wrapper (useNotifyX) instead.', + }, + ], + }, + ], }, globals: {}, @@ -137,5 +159,12 @@ module.exports = { 'cypress/unsafe-to-chain-command': 'warn', }, }, + // Allow HTTP hooks in notification wrappers and tests + { + files: ['app/src/resources/**', '**/__tests__/**test**'], + rules: { + 'no-restricted-imports': 'off', + }, + }, ], } diff --git a/.github/actions/python/setup/action.yaml b/.github/actions/python/setup/action.yaml index 5e728acb9c9..c90563ccd1f 100644 --- a/.github/actions/python/setup/action.yaml +++ b/.github/actions/python/setup/action.yaml @@ -14,6 +14,8 @@ runs: - shell: bash run: | if [[ "${OSTYPE}" =~ "linux" ]]; then + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list sudo apt-get update sudo apt-get install -y --no-install-recommends libsystemd-dev fi diff --git a/.github/workflows/app-test-build-deploy.yaml b/.github/workflows/app-test-build-deploy.yaml index 8d0658a930e..878a875bdfc 100644 --- a/.github/workflows/app-test-build-deploy.yaml +++ b/.github/workflows/app-test-build-deploy.yaml @@ -61,7 +61,10 @@ jobs: with: node-version: '18.19.0' - name: 'install udev' - run: sudo apt-get update && sudo apt-get install libudev-dev + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev - name: 'set complex environment variables' id: 'set-vars' uses: actions/github-script@v6 @@ -112,13 +115,14 @@ jobs: - uses: actions/setup-python@v4 with: python-version: '3.10' - - name: 'downgrade npm version' - run: npm install -g npm@6 - name: check make version run: make --version - name: 'install libudev and libsystemd' if: startsWith(matrix.os, 'ubuntu') - run: sudo apt-get update && sudo apt-get install libudev-dev + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev - name: 'set complex environment variables' id: 'set-vars' uses: actions/github-script@v6 @@ -245,13 +249,14 @@ jobs: - uses: actions/setup-python@v4 with: python-version: '3.10' - - name: 'downgrade npm version' - run: npm install -g npm@6 - name: check make version run: make --version - name: 'install libudev and libsystemd' if: startsWith(matrix.os, 'ubuntu') - run: sudo apt-get update && sudo apt-get install libudev-dev + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev - name: 'set complex environment variables' id: 'set-vars' uses: actions/github-script@v6 @@ -427,7 +432,10 @@ jobs: with: node-version: '18.19.0' - name: 'install udev' - run: sudo apt-get update && sudo apt-get install libudev-dev + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev - name: 'set complex environment variables' id: 'set-vars' uses: actions/github-script@v6 diff --git a/.github/workflows/components-test-build-deploy.yaml b/.github/workflows/components-test-build-deploy.yaml index 78e60426b3f..7d4f2f5f49a 100644 --- a/.github/workflows/components-test-build-deploy.yaml +++ b/.github/workflows/components-test-build-deploy.yaml @@ -44,7 +44,10 @@ jobs: with: node-version: '18.19.0' - name: 'install udev for usb-detection' - run: sudo apt-get update && sudo apt-get install libudev-dev + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev - name: 'cache yarn cache' uses: actions/cache@v3 with: @@ -77,7 +80,10 @@ jobs: with: node-version: '18.19.0' - name: 'install udev for usb-detection' - run: sudo apt-get update && sudo apt-get install libudev-dev + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev - name: 'cache yarn cache' uses: actions/cache@v3 with: @@ -174,10 +180,16 @@ jobs: with: node-version: '18.19.0' registry-url: 'https://registry.npmjs.org' + - name: 'install udev for usb-detection' + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev - name: 'setup-js' run: | npm config set cache ./.npm-cache yarn config set cache-folder ./.yarn-cache + make setup-js - name: 'build typescript' run: make build-ts - name: 'build library' diff --git a/.github/workflows/g-code-testing-lint-test.yaml b/.github/workflows/g-code-testing-lint-test.yaml index 89fe00f4d2d..e174bc7ac52 100644 --- a/.github/workflows/g-code-testing-lint-test.yaml +++ b/.github/workflows/g-code-testing-lint-test.yaml @@ -46,7 +46,10 @@ jobs: with: fetch-depth: 0 - name: 'install udev' - run: sudo apt-get update && sudo apt-get install libudev-dev + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev - uses: 'actions/setup-node@v3' with: node-version: '18.19.0' diff --git a/.github/workflows/js-check.yaml b/.github/workflows/js-check.yaml index b880cb33d48..8a02c1823ba 100644 --- a/.github/workflows/js-check.yaml +++ b/.github/workflows/js-check.yaml @@ -54,7 +54,10 @@ jobs: const { buildComplexEnvVars } = require(`${process.env.GITHUB_WORKSPACE}/.github/workflows/utils.js`) buildComplexEnvVars(core, context) - name: 'install libudev for usb-detection' - run: sudo apt-get update && sudo apt-get install libudev-dev + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev - name: 'cache yarn cache' uses: actions/cache@v3 with: diff --git a/.github/workflows/ll-test-build-deploy.yaml b/.github/workflows/ll-test-build-deploy.yaml index d25cfaab3aa..140537593e2 100644 --- a/.github/workflows/ll-test-build-deploy.yaml +++ b/.github/workflows/ll-test-build-deploy.yaml @@ -53,7 +53,10 @@ jobs: git fetch -f origin ${{ github.ref }}:${{ github.ref }} git checkout ${{ github.ref }} - name: 'install libudev for usb-detection' - run: sudo apt-get update && sudo apt-get install libudev-dev + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev - name: 'cache yarn cache' uses: actions/cache@v3 with: @@ -93,7 +96,10 @@ jobs: with: node-version: '18.19.0' - name: 'install libudev for usb-detection' - run: sudo apt-get update && sudo apt-get install libudev-dev + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev - name: 'cache yarn cache' uses: actions/cache@v3 with: @@ -133,7 +139,10 @@ jobs: with: node-version: '18.19.0' - name: 'install libudev for usb-detection' - run: sudo apt-get update && sudo apt-get install libudev-dev + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev - name: 'cache yarn cache' uses: actions/cache@v3 with: @@ -176,7 +185,10 @@ jobs: with: node-version: '18.19.0' - name: 'install udev for usb-detection' - run: sudo apt-get update && sudo apt-get install libudev-dev + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev - name: 'set complex environment variables' id: 'set-vars' uses: actions/github-script@v6 diff --git a/.github/workflows/opentrons-ai-client-test-build-deploy.yaml b/.github/workflows/opentrons-ai-client-test-build-deploy.yaml new file mode 100644 index 00000000000..2f569d9bf78 --- /dev/null +++ b/.github/workflows/opentrons-ai-client-test-build-deploy.yaml @@ -0,0 +1,81 @@ +# Run tests, build the app, and deploy it cross platform + +name: 'OpentronsAI client test, build, and deploy' + +# ToDo (kk:04/16/2024) Add build and deploy task + +on: + push: + paths: + - 'Makefile' + - 'opentrons-ai-client/**/*' + - 'components/**/*' + - '*.js' + - '*.json' + - 'yarn.lock' + - '.github/workflows/app-test-build-deploy.yaml' + - '.github/workflows/utils.js' + branches: + - '**' + tags: + - 'v*' + - 'ot3@*' + pull_request: + paths: + - 'Makefile' + - 'opentrons-ai-client/**/*' + - 'components/**/*' + - '*.js' + - '*.json' + - 'yarn.lock' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}-${{ github.ref_name != 'edge' || github.run_id}}-${{ github.ref_type != 'tag' || github.run_id }} + cancel-in-progress: true + +env: + CI: true + +jobs: + js-unit-test: + runs-on: 'ubuntu-22.04' + name: 'opentrons ai frontend unit tests' + timeout-minutes: 60 + steps: + - uses: 'actions/checkout@v3' + - uses: 'actions/setup-node@v3' + with: + node-version: '18.19.0' + - name: 'install udev' + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev + - name: 'set complex environment variables' + id: 'set-vars' + uses: actions/github-script@v6 + with: + script: | + const { buildComplexEnvVars } = require(`${process.env.GITHUB_WORKSPACE}/.github/workflows/utils.js`) + buildComplexEnvVars(core, context) + - name: 'cache yarn cache' + uses: actions/cache@v3 + with: + path: | + ${{ github.workspace }}/.npm-cache/_prebuild + ${{ github.workspace }}/.yarn-cache + key: js-${{ secrets.GH_CACHE_VERSION }}-${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} + - name: 'setup-js' + run: | + npm config set cache ${{ github.workspace }}/.npm-cache + yarn config set cache-folder ${{ github.workspace }}/.yarn-cache + make setup-js + - name: 'test frontend packages' + run: | + make -C opentrons-ai-client test-cov + - name: 'Upload coverage report' + uses: codecov/codecov-action@v3 + with: + files: ./coverage/lcov.info + flags: opentrons-ai-client diff --git a/.github/workflows/pd-test-build-deploy.yaml b/.github/workflows/pd-test-build-deploy.yaml index f2af41620be..9f23419da94 100644 --- a/.github/workflows/pd-test-build-deploy.yaml +++ b/.github/workflows/pd-test-build-deploy.yaml @@ -53,7 +53,10 @@ jobs: with: node-version: '18.19.0' - name: 'install udev for usb-detection' - run: sudo apt-get update && sudo apt-get install libudev-dev + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev - name: 'cache yarn cache' uses: actions/cache@v2 with: @@ -99,7 +102,10 @@ jobs: node-version: '18.19.0' - name: 'install udev for usb-detection' if: startsWith(matrix.os, 'ubuntu') - run: sudo apt-get update && sudo apt-get install libudev-dev + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev - name: 'cache yarn cache' uses: actions/cache@v3 with: @@ -135,7 +141,10 @@ jobs: with: node-version: '18.19.0' - name: 'install udev for usb-detection' - run: sudo apt-get update && sudo apt-get install libudev-dev + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev - name: 'cache yarn cache' uses: actions/cache@v3 with: @@ -176,7 +185,10 @@ jobs: with: node-version: '18.19.0' - name: 'install udev for usb-detection' - run: sudo apt-get update && sudo apt-get install libudev-dev + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev - name: 'set complex environment variables' id: 'set-vars' uses: actions/github-script@v6 diff --git a/.github/workflows/performance-metrics-test-lint.yaml b/.github/workflows/performance-metrics-test-lint.yaml new file mode 100644 index 00000000000..e57df828caf --- /dev/null +++ b/.github/workflows/performance-metrics-test-lint.yaml @@ -0,0 +1,54 @@ +# This workflow runs lint on pull requests that touch anything in the performance-metrics directory + +name: 'performance-metrics test & lint' + +on: + pull_request: + paths: + - 'performance-metrics/**' + - '.github/workflows/performance-metrics-test-lint.yaml' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +defaults: + run: + shell: bash + +jobs: + lint: + name: 'performance-metrics test & lint' + timeout-minutes: 5 + runs-on: 'ubuntu-latest' + steps: + - name: Checkout opentrons repo + uses: 'actions/checkout@v4' + + - name: Setup Python + uses: 'actions/setup-python@v5' + with: + python-version: '3.10' + cache: 'pipenv' + cache-dependency-path: performance-metrics/Pipfile.lock + + - name: "Install Python deps" + uses: './.github/actions/python/setup' + with: + project: 'performance-metrics' + + - name: Setup + id: install + working-directory: ./performance-metrics + run: make setup + + - name: Test + if: always() && steps.install.outcome == 'success' || steps.install.outcome == 'skipped' + working-directory: ./performance-metrics + run: make test + + - name: Lint + if: always() && steps.install.outcome == 'success' || steps.install.outcome == 'skipped' + working-directory: ./performance-metrics + run: make lint diff --git a/.github/workflows/react-api-client-test.yaml b/.github/workflows/react-api-client-test.yaml index af8e4015497..a8f5ed959b2 100644 --- a/.github/workflows/react-api-client-test.yaml +++ b/.github/workflows/react-api-client-test.yaml @@ -41,7 +41,10 @@ jobs: with: node-version: '18.19.0' - name: 'install libudev for usb-detection' - run: sudo apt-get update && sudo apt-get install libudev-dev + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev - name: 'cache yarn cache' uses: actions/cache@v3 with: diff --git a/.github/workflows/shared-data-test-lint-deploy.yaml b/.github/workflows/shared-data-test-lint-deploy.yaml index 94c56f16a56..56dcf76f00a 100644 --- a/.github/workflows/shared-data-test-lint-deploy.yaml +++ b/.github/workflows/shared-data-test-lint-deploy.yaml @@ -80,7 +80,10 @@ jobs: fetch-depth: 0 - name: 'install udev for usb-detection' if: startsWith(matrix.os, 'ubuntu') - run: sudo apt-get update && sudo apt-get install libudev-dev + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev - uses: 'actions/setup-node@v1' with: node-version: '18.19.0' @@ -117,7 +120,10 @@ jobs: with: node-version: '18.19.0' - name: 'install udev' - run: sudo apt-get update && sudo apt-get install libudev-dev + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev - name: 'cache yarn cache' uses: actions/cache@v3 with: @@ -159,7 +165,10 @@ jobs: with: node-version: '18.19.0' - name: 'install udev for usb-detection' - run: sudo apt-get update && sudo apt-get install libudev-dev + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev - uses: 'actions/setup-python@v4' with: python-version: '3.10' @@ -237,7 +246,8 @@ jobs: - name: 'js deps' run: | npm config set cache ./.npm-cache - yarn config set cache-folder ./.yarn-cache + yarn config set cache-folder ./.yarn-cache + make setup-js - name: 'build typescript' run: make build-ts - name: 'build library' diff --git a/.github/workflows/step-generation-test.yaml b/.github/workflows/step-generation-test.yaml index a0a9f7fef09..7ac65f3997e 100644 --- a/.github/workflows/step-generation-test.yaml +++ b/.github/workflows/step-generation-test.yaml @@ -40,7 +40,10 @@ jobs: with: node-version: '18.19.0' - name: 'install udev for usb-detection' - run: sudo apt-get update && sudo apt-get install libudev-dev + run: | + # WORKAROUND: Remove microsoft debian repo due to https://github.com/microsoft/linux-package-repositories/issues/130. Remove line below after it is resolved + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get update && sudo apt-get install libudev-dev - name: 'cache yarn cache' uses: actions/cache@v3 with: diff --git a/.gitignore b/.gitignore index e7de830c6a1..7d32575773a 100755 --- a/.gitignore +++ b/.gitignore @@ -161,3 +161,4 @@ opentrons-robot-app.tar.gz .tool-versions mock_dir .npm-cache/ +.eslintcache diff --git a/.storybook/main.js b/.storybook/main.js index e9fc91cdf48..985486d5d4e 100644 --- a/.storybook/main.js +++ b/.storybook/main.js @@ -2,6 +2,7 @@ module.exports = { stories: [ '../components/**/*.stories.@(js|jsx|ts|tsx)', '../app/**/*.stories.@(js|jsx|ts|tsx)', + '../opentrons-ai-client/**/*.stories.@(js|jsx|ts|tsx)', ], addons: [ diff --git a/.storybook/preview.jsx b/.storybook/preview.jsx index d8537e57827..32864c9abcb 100644 --- a/.storybook/preview.jsx +++ b/.storybook/preview.jsx @@ -20,7 +20,7 @@ export const parameters = { options: { storySort: { method: 'alphabetical', - order: ['Design Tokens', 'Library', 'App', 'ODD'], + order: ['Design Tokens', 'Library', 'App', 'ODD', 'AI'], }, }, } diff --git a/Makefile b/Makefile index 1b2bbf42b82..c24e2751137 100755 --- a/Makefile +++ b/Makefile @@ -215,10 +215,17 @@ lint-py: $(PYTHON_LINT_TARGETS) $(MAKE) -C $* lint .PHONY: lint-js -lint-js: - yarn eslint --quiet=$(quiet) ".*.@(js|ts|tsx)" "**/*.@(js|ts|tsx)" +lint-js: lint-js-eslint lint-js-prettier + +.PHONY: lint-js-eslint +lint-js-eslint: + yarn eslint --quiet=$(quiet) --ignore-pattern "node_modules/" --cache ".*.@(js|ts|tsx)" "**/*.@(js|ts|tsx)" + +.PHONY: lint-js-prettier +lint-js-prettier: yarn prettier --ignore-path .eslintignore --check $(FORMAT_FILE_GLOB) + .PHONY: lint-json lint-json: yarn eslint --max-warnings 0 --ext .json . diff --git a/abr-testing/abr_testing/automation/google_drive_tool.py b/abr-testing/abr_testing/automation/google_drive_tool.py index 3b65456d0ff..dbaba0d1ecc 100644 --- a/abr-testing/abr_testing/automation/google_drive_tool.py +++ b/abr-testing/abr_testing/automation/google_drive_tool.py @@ -1,11 +1,16 @@ """Google Drive Tool.""" import os -from typing import Set, Any, Optional +import io +import json +import sys +from typing import Set, Any, Optional, List, Dict import webbrowser import mimetypes from oauth2client.service_account import ServiceAccountCredentials # type: ignore[import] +import googleapiclient # type: ignore[import] from googleapiclient.discovery import build from googleapiclient.http import MediaFileUpload +from googleapiclient.http import MediaIoBaseDownload """Google Drive Tool. @@ -18,13 +23,17 @@ class google_drive: def __init__(self, credentials: Any, folder_name: str, email: str) -> None: """Connects to google drive via credentials file.""" - self.scope = ["https://www.googleapis.com/auth/drive"] - self.credentials = ServiceAccountCredentials.from_json_keyfile_name( - credentials, self.scope - ) - self.drive_service = build("drive", "v3", credentials=self.credentials) - self.parent_folder = folder_name - self.email = email + try: + self.scope = ["https://www.googleapis.com/auth/drive"] + self.credentials = ServiceAccountCredentials.from_json_keyfile_name( + credentials, self.scope + ) + self.drive_service = build("drive", "v3", credentials=self.credentials) + self.parent_folder = folder_name + self.email = email + except json.decoder.JSONDecodeError: + print("Error! Get file: https://console.cloud.google.com/apis/credentials") + sys.exit() def list_folder(self, delete: Any = False) -> Set[str]: """List folders and files in Google Drive.""" @@ -58,7 +67,6 @@ def list_folder(self, delete: Any = False) -> Set[str]: break if not file_names: print("No folders or files found in Google Drive.") - print(f"{len(file_names)} item(s) in Google Drive") return file_names def delete_files(self, file_or_folder_id: str) -> None: @@ -88,7 +96,7 @@ def upload_file(self, file_path: str) -> str: def upload_missing_files(self, storage_directory: str) -> None: """Upload missing files to Google Drive.""" - # Read Google Drive .json files. + # Read .json files. google_drive_files = self.list_folder() google_drive_files_json = [ file for file in google_drive_files if file.endswith(".json") @@ -98,18 +106,22 @@ def upload_missing_files(self, storage_directory: str) -> None: file for file in os.listdir(storage_directory) if file.endswith(".json") ) missing_files = local_files_json - set(google_drive_files_json) - print(f"Missing files: {len(missing_files)}") # Upload missing files. uploaded_files = [] for file in missing_files: file_path = os.path.join(storage_directory, file) uploaded_file_id = google_drive.upload_file(self, file_path) - self.share_permissions(uploaded_file_id) uploaded_files.append( {"name": os.path.basename(file_path), "id": uploaded_file_id} ) - # Fetch the updated file list after all files are uploaded + try: + self.share_permissions(uploaded_file_id) + except googleapiclient.errors.HttpError: + continue + + # Fetch the updated file list after all are uploaded files = google_drive.list_folder(self) + file_names = [file for file in files] for uploaded_file in uploaded_files: this_name = uploaded_file["name"] @@ -118,9 +130,8 @@ def upload_missing_files(self, storage_directory: str) -> None: f"File '{this_name}' was successfully uploaded with ID: {uploaded_file['id']}" ) else: - print( - f"File '{this_name}' was not found in the list of files after uploading." - ) + print(f"File '{this_name}' was not found after uploading.") + print(f"{len(files)} item(s) in Google Drive") def open_folder(self) -> Optional[str]: """Open folder in web browser.""" @@ -149,3 +160,32 @@ def share_permissions(self, file_id: str) -> None: self.drive_service.permissions().create( fileId=file_id, body=new_permission, transferOwnership=False # type: ignore ).execute() + + def download_files( + self, files_to_download: List[Dict[str, Any]], save_directory: str + ) -> None: + """Download files to a specified directory.""" + for file in files_to_download: + id = file["id"] + file_name = file["name"] + file_path = os.path.join(save_directory, file_name) + request = self.drive_service.files().get_media(fileId=id) # type: ignore[attr-defined] + fh = io.FileIO(file_path, "wb") + downloader = MediaIoBaseDownload(fh, request) + done = False + while done is False: + status, done = downloader.next_chunk() + print(f"Downloading {file_name}... {int(status.progress() * 100)}%") + + def search_folder(self, search_strings: List[str], folder_id: str) -> List[Any]: + """Search folder for files containing string from list.""" + files_found = [] + for search_string in search_strings: + query = f"'{folder_id}' in parents and name contains '{search_string}'" + response = ( + self.drive_service.files() + .list(q=query, fields="files(id,name)") + .execute() + ) + files_found.extend(response.get("files", [])) + return files_found diff --git a/abr-testing/abr_testing/automation/google_sheets_tool.py b/abr-testing/abr_testing/automation/google_sheets_tool.py index af38a39dcc0..e132422a482 100644 --- a/abr-testing/abr_testing/automation/google_sheets_tool.py +++ b/abr-testing/abr_testing/automation/google_sheets_tool.py @@ -2,6 +2,8 @@ import gspread # type: ignore[import] import socket import httplib2 +import time as t +import sys from datetime import datetime from oauth2client.service_account import ServiceAccountCredentials # type: ignore[import] from typing import Dict, List, Any, Set, Tuple @@ -18,19 +20,24 @@ class google_sheet: def __init__(self, credentials: Any, file_name: str, tab_number: int) -> None: """Connects to google sheet via credentials file.""" - self.scope = [ - "https://spreadsheets.google.com/feeds", - "https://www.googleapis.com/auth/drive", - ] - self.credentials = ServiceAccountCredentials.from_json_keyfile_name( - credentials, self.scope - ) - self.gc = gspread.authorize(self.credentials) - self.file_name = file_name - self.tab_number = tab_number - self.spread_sheet = self.open_google_sheet() - self.worksheet = self.open_worksheet(self.tab_number) - self.row_index = 1 + try: + self.scope = [ + "https://spreadsheets.google.com/feeds", + "https://www.googleapis.com/auth/drive", + ] + self.credentials = ServiceAccountCredentials.from_json_keyfile_name( + credentials, self.scope + ) + self.gc = gspread.authorize(self.credentials) + self.file_name = file_name + self.tab_number = tab_number + self.spread_sheet = self.open_google_sheet() + self.worksheet = self.open_worksheet(self.tab_number) + self.row_index = 1 + print(f"Connected to google sheet: {self.file_name}") + except gspread.exceptions.APIError: + print("ERROR: Check google sheet name. Check credentials file.") + sys.exit() def open_google_sheet(self) -> Any: """Open Google Spread Sheet.""" @@ -71,10 +78,14 @@ def write_to_row(self, data: List) -> None: print("UNABLE TO CONNECT TO SERVER!!, CHECK CONNECTION") except Exception as error: print(error.__traceback__) + except gspread.exceptions.APIError: + print("Write quotes exceeded. Waiting 30 sec before writing.") + t.sleep(30) + self.worksheet.insert_row(data, index=self.row_index) def delete_row(self, row_index: int) -> None: """Delete Row from google sheet.""" - self.worksheet.delete_row(row_index) + self.worksheet.delete_rows(row_index) def update_cell( self, row: int, column: int, single_data: Any @@ -94,7 +105,7 @@ def get_column(self, column_number: int) -> Set[str]: def get_index_row(self) -> int: """Check for the next available row to write too.""" row_index = len(self.get_column(1)) - print("Row Index: ", row_index) + print(f"Row Index: {row_index} recorded on google sheet.") return row_index def update_row_index(self) -> None: @@ -120,3 +131,13 @@ def token_check(self) -> None: """Check if still credentials are still logged in.""" if self.credentials.access_token_expired: self.gc.login() + + def get_row_index_with_value(self, some_string: str, col_num: int) -> Any: + """Find row index of string by looking in specific column.""" + cell = self.worksheet.find(some_string, in_column=col_num) + try: + row_index = int(cell.row) + except AttributeError: + print("Row not found.") + return None + return row_index diff --git a/abr-testing/abr_testing/data_collection/abr_calibration_logs.py b/abr-testing/abr_testing/data_collection/abr_calibration_logs.py index 4d744b5b2f5..82d9d9c45bc 100644 --- a/abr-testing/abr_testing/data_collection/abr_calibration_logs.py +++ b/abr-testing/abr_testing/data_collection/abr_calibration_logs.py @@ -3,8 +3,8 @@ import argparse import os import json -import gspread # type: ignore[import] import sys +import time as t from abr_testing.data_collection import read_robot_logs from abr_testing.automation import google_drive_tool, google_sheets_tool @@ -18,16 +18,20 @@ def check_for_duplicates( headers: List[str], ) -> Union[List[str], None]: """Check google sheet for duplicates.""" + t.sleep(5) serials = google_sheet.get_column(col_1) modify_dates = google_sheet.get_column(col_2) - # check for complete calibration. - if len(row[-1]) > 0: - for serial, modify_date in zip(serials, modify_dates): - if row[col_1 - 1] == serial and row[col_2 - 1] == modify_date: - print(f"Skipped row for instrument {serial}. Already on Google Sheet.") - return None - read_robot_logs.write_to_sheets(sheet_location, google_sheet, row, headers) - print(f"Writing calibration for: {serial}") + # Check for calibration time stamp. + if row[-1] is not None: + if len(row[-1]) > 0: + for serial, modify_date in zip(serials, modify_dates): + if row[col_1 - 1] == serial and row[col_2 - 1] == modify_date: + print( + f"Skipped row for instrument {serial}. Already on Google Sheet." + ) + return None + read_robot_logs.write_to_sheets(sheet_location, google_sheet, row, headers) + print(f"Writing calibration for: {row[7]}") return row @@ -151,18 +155,10 @@ def upload_calibration_offsets( parser.add_argument( "email", metavar="EMAIL", type=str, nargs=1, help="opentrons gmail." ) - parser.add_argument( - "ip_or_all", - metavar="IP_OR_ALL", - type=str, - nargs=1, - help="Enter 'ALL' to read IPs.json or type full IP address of 1 robot.", - ) args = parser.parse_args() storage_directory = args.storage_directory[0] folder_name = args.folder_name[0] google_sheet_name = args.google_sheet_name[0] - ip_or_all = args.ip_or_all[0] email = args.email[0] # Connect to google drive. try: @@ -170,51 +166,32 @@ def upload_calibration_offsets( except FileNotFoundError: print(f"Add credentials.json file to: {storage_directory}.") sys.exit() - try: - google_drive = google_drive_tool.google_drive( - credentials_path, folder_name, email - ) - # Upload calibration logs to google drive. - print("Connected to google drive.") - except json.decoder.JSONDecodeError: - print( - "Credential file is damaged. Get from https://console.cloud.google.com/apis/credentials" - ) - sys.exit() + google_drive = google_drive_tool.google_drive(credentials_path, folder_name, email) # Connect to google sheet - try: - google_sheet_instruments = google_sheets_tool.google_sheet( - credentials_path, google_sheet_name, 0 - ) - google_sheet_modules = google_sheets_tool.google_sheet( - credentials_path, google_sheet_name, 1 - ) - google_sheet_deck = google_sheets_tool.google_sheet( - credentials_path, google_sheet_name, 2 - ) - print(f"Connected to google sheet: {google_sheet_name}") - except gspread.exceptions.APIError: - print("ERROR: Check google sheet name. Check credentials file.") - sys.exit() + google_sheet_instruments = google_sheets_tool.google_sheet( + credentials_path, google_sheet_name, 0 + ) + google_sheet_modules = google_sheets_tool.google_sheet( + credentials_path, google_sheet_name, 1 + ) + google_sheet_deck = google_sheets_tool.google_sheet( + credentials_path, google_sheet_name, 2 + ) ip_json_file = os.path.join(storage_directory, "IPs.json") try: ip_file = json.load(open(ip_json_file)) except FileNotFoundError: print(f"Add .json file with robot IPs to: {storage_directory}.") sys.exit() + ip_or_all = input("IP Address or ALL: ") if ip_or_all == "ALL": ip_address_list = ip_file["ip_address_list"] for ip in ip_address_list: - print(ip) - try: - saved_file_path, calibration = read_robot_logs.get_calibration_offsets( - ip, storage_directory - ) - upload_calibration_offsets(calibration, storage_directory) - except Exception: - print(f"ERROR: Failed to read IP address: {ip}") - continue + saved_file_path, calibration = read_robot_logs.get_calibration_offsets( + ip, storage_directory + ) + upload_calibration_offsets(calibration, storage_directory) else: saved_file_path, calibration = read_robot_logs.get_calibration_offsets( ip_or_all, storage_directory diff --git a/abr-testing/abr_testing/data_collection/abr_google_drive.py b/abr-testing/abr_testing/data_collection/abr_google_drive.py index 6470f1e0410..f8a2dc8fa4f 100644 --- a/abr-testing/abr_testing/data_collection/abr_google_drive.py +++ b/abr-testing/abr_testing/data_collection/abr_google_drive.py @@ -3,7 +3,6 @@ import os import sys import json -import gspread # type: ignore[import] from datetime import datetime, timedelta from abr_testing.data_collection import read_robot_logs from typing import Set, Dict, Any, Tuple, List, Union @@ -43,6 +42,8 @@ def create_data_dictionary( file_results = json.load(file) else: continue + if not isinstance(file_results, dict): + continue run_id = file_results.get("run_id", "NaN") if run_id in runs_to_save: robot = file_results.get("robot_name") @@ -107,13 +108,18 @@ def create_data_dictionary( hs_dict = read_robot_logs.hs_commands(file_results) tm_dict = read_robot_logs.temperature_module_commands(file_results) notes = {"Note1": "", "Jira Link": issue_url} - row_2 = {**row, **all_modules, **notes, **hs_dict, **tm_dict, **tc_dict} + row_2 = { + **row, + **all_modules, + **notes, + **hs_dict, + **tm_dict, + **tc_dict, + } headers = list(row_2.keys()) runs_and_robots[run_id] = row_2 else: continue - # os.remove(file_path) - # print(f"Run ID: {run_id} has a run time of 0 minutes. Run removed.") return runs_and_robots, headers @@ -153,33 +159,13 @@ def create_data_dictionary( except FileNotFoundError: print(f"Add credentials.json file to: {storage_directory}.") sys.exit() - try: - google_drive = google_drive_tool.google_drive( - credentials_path, folder_name, email - ) - print("Connected to google drive.") - except json.decoder.JSONDecodeError: - print( - "Credential file is damaged. Get from https://console.cloud.google.com/apis/credentials" - ) - sys.exit() + google_drive = google_drive_tool.google_drive(credentials_path, folder_name, email) # Get run ids on google sheet - try: - google_sheet = google_sheets_tool.google_sheet( - credentials_path, google_sheet_name, 0 - ) - print(f"Connected to google sheet: {google_sheet_name}") - except gspread.exceptions.APIError: - print("ERROR: Check google sheet name. Check credentials file.") - sys.exit() - try: - google_sheet_lpc = google_sheets_tool.google_sheet( - credentials_path, "ABR-LPC", 0 - ) - print("Connected to google sheet ABR-LPC") - except gspread.exceptions.APIError: - print("ERROR: Check google sheet name. Check credentials file.") - sys.exit() + google_sheet = google_sheets_tool.google_sheet( + credentials_path, google_sheet_name, 0 + ) + google_sheet_lpc = google_sheets_tool.google_sheet(credentials_path, "ABR-LPC", 0) + run_ids_on_gs = google_sheet.get_column(2) run_ids_on_gs = set(run_ids_on_gs) diff --git a/abr-testing/abr_testing/data_collection/abr_robot_error.py b/abr-testing/abr_testing/data_collection/abr_robot_error.py index b139b5a3ade..231b8077eed 100644 --- a/abr-testing/abr_testing/data_collection/abr_robot_error.py +++ b/abr-testing/abr_testing/data_collection/abr_robot_error.py @@ -91,13 +91,6 @@ def get_error_info_from_robot( nargs=1, help="Path to long term storage directory for run logs.", ) - parser.add_argument( - "robot_ip", - metavar="ROBOT_IP", - type=str, - nargs=1, - help="IP address of robot as string.", - ) parser.add_argument( "jira_api_token", metavar="JIRA_API_TOKEN", @@ -130,14 +123,18 @@ def get_error_info_from_robot( ) args = parser.parse_args() storage_directory = args.storage_directory[0] - ip = args.robot_ip[0] + ip = str(input("Enter Robot IP: ")) url = "https://opentrons.atlassian.net" api_token = args.jira_api_token[0] email = args.email[0] board_id = args.board_id[0] reporter_id = args.reporter_id[0] ticket = jira_tool.JiraTicket(url, api_token, email) - error_runs = get_error_runs_from_robot(ip) + try: + error_runs = get_error_runs_from_robot(ip) + except requests.exceptions.InvalidURL: + print("Invalid IP address.") + sys.exit() one_run = error_runs[-1] # Most recent run with error. ( summary, @@ -147,7 +144,7 @@ def get_error_info_from_robot( whole_description_str, run_log_file_path, ) = get_error_info_from_robot(ip, one_run, storage_directory) - # get calibration data + # Get Calibration Data saved_file_path_calibration, calibration = read_robot_logs.get_calibration_offsets( ip, storage_directory ) @@ -156,6 +153,7 @@ def get_error_info_from_robot( # TODO: make argument or see if I can get rid of with using board_id. project_key = "RABR" parent_key = project_key + "-" + robot[-1] + # TODO: read board to see if ticket for run id already exists. # CREATE TICKET issue_key = ticket.create_ticket( summary, @@ -172,7 +170,7 @@ def get_error_info_from_robot( issue_url = ticket.open_issue(issue_key) # MOVE FILES TO ERROR FOLDER. error_files = [saved_file_path_calibration, run_log_file_path] + file_paths - error_folder_path = os.path.join(storage_directory, str("RABR-238")) + error_folder_path = os.path.join(storage_directory, issue_key) os.makedirs(error_folder_path, exist_ok=True) for source_file in error_files: destination_file = os.path.join( diff --git a/abr-testing/abr_testing/data_collection/get_run_logs.py b/abr-testing/abr_testing/data_collection/get_run_logs.py index 4034f076dc9..70b0e3f680a 100644 --- a/abr-testing/abr_testing/data_collection/get_run_logs.py +++ b/abr-testing/abr_testing/data_collection/get_run_logs.py @@ -104,13 +104,10 @@ def get_all_run_logs(storage_directory: str) -> None: ip_address_list = ip_file["ip_address_list"] runs_from_storage = read_robot_logs.get_run_ids_from_google_drive(google_drive) for ip in ip_address_list: - try: - runs = get_run_ids_from_robot(ip) - runs_to_save = read_robot_logs.get_unseen_run_ids(runs, runs_from_storage) - save_runs(runs_to_save, ip, storage_directory) - google_drive.upload_missing_files(storage_directory) - except Exception: - print(f"ERROR: Failed to read IP address: {ip}.") + runs = get_run_ids_from_robot(ip) + runs_to_save = read_robot_logs.get_unseen_run_ids(runs, runs_from_storage) + save_runs(runs_to_save, ip, storage_directory) + google_drive.upload_missing_files(storage_directory) if __name__ == "__main__": @@ -142,14 +139,5 @@ def get_all_run_logs(storage_directory: str) -> None: except FileNotFoundError: print(f"Add credentials.json file to: {storage_directory}.") sys.exit() - try: - google_drive = google_drive_tool.google_drive( - credentials_path, folder_name, email - ) - print("Connected to google drive.") - except json.decoder.JSONDecodeError: - print( - "Credential file is damaged. Get from https://console.cloud.google.com/apis/credentials" - ) - sys.exit() + google_drive = google_drive_tool.google_drive(credentials_path, folder_name, email) get_all_run_logs(storage_directory) diff --git a/abr-testing/abr_testing/data_collection/module_ramp_rates.py b/abr-testing/abr_testing/data_collection/module_ramp_rates.py new file mode 100644 index 00000000000..2155e79dc21 --- /dev/null +++ b/abr-testing/abr_testing/data_collection/module_ramp_rates.py @@ -0,0 +1,148 @@ +"""Get ramp rates of modules.""" +from abr_testing.automation import google_sheets_tool +from abr_testing.data_collection import read_robot_logs +import argparse +import os +import sys +import json +from datetime import datetime +from typing import Dict, Any +import requests + + +def ramp_rate(file_results: Dict[str, Any]) -> Dict[int, float]: + """Get ramp rates.""" + i = 0 + commands = file_results["commands"] + for command in commands: + commandType = command["commandType"] + if ( + commandType == "thermocycler/setTargetBlockTemperature" + or commandType == "temperatureModule/setTargetTemperature" + or commandType == "heaterShaker/setTargetTemperature" + ): + temp = command["params"].get("celsius", 0.0) + if ( + commandType == "thermocycler/waitForBlockTemperature" + or commandType == "temperatureModule/waitForTemperature" + or commandType == "heaterShaker/waitForTemperature" + ): + start_time = datetime.strptime( + command.get("startedAt", ""), "%Y-%m-%dT%H:%M:%S.%f%z" + ) + end_time = datetime.strptime( + command.get("completedAt", ""), "%Y-%m-%dT%H:%M:%S.%f%z" + ) + duration = (end_time - start_time).total_seconds() + i += 1 + temps_and_durations[duration] = temp + ramp_rates = {} + times = list(temps_and_durations.keys()) + for i in range(len(times) - 1): + time1 = times[i] + time2 = times[i + 1] + temp1 = temps_and_durations[time1] + temp2 = temps_and_durations[time2] + ramp_rate = (temp2 - temp1) / (time2) + ramp_rates[i] = ramp_rate + return ramp_rates + + +if __name__ == "__main__": + # SCRIPT ARGUMENTS + parser = argparse.ArgumentParser(description="Read run logs on google drive.") + parser.add_argument( + "storage_directory", + metavar="STORAGE_DIRECTORY", + type=str, + nargs=1, + help="Path to long term storage directory for run logs.", + ) + parser.add_argument( + "google_sheet_name", + metavar="GOOGLE_SHEET_NAME", + type=str, + nargs=1, + help="Google sheet name.", + ) + parser.add_argument( + "email", metavar="EMAIL", type=str, nargs=1, help="opentrons gmail." + ) + args = parser.parse_args() + storage_directory = args.storage_directory[0] + google_sheet_name = args.google_sheet_name[0] + # FIND CREDENTIALS FILE + try: + credentials_path = os.path.join(storage_directory, "credentials.json") + except FileNotFoundError: + print(f"Add credentials.json file to: {storage_directory}.") + sys.exit() + # CONNECT TO GOOGLE SHEET + google_sheet = google_sheets_tool.google_sheet( + credentials_path, google_sheet_name, 1 + ) + run_ids_on_sheet = google_sheet.get_column(2) + runs_and_robots = {} + for filename in os.listdir(storage_directory): + file_path = os.path.join(storage_directory, filename) + if file_path.endswith(".json"): + with open(file_path) as file: + file_results = json.load(file) + else: + continue + # CHECK if file is ramp rate run + run_id = file_results.get("run_id", None) + temps_and_durations: Dict[float, float] = dict() + if run_id is not None and run_id not in run_ids_on_sheet: + + ramp_rates = ramp_rate(file_results) + protocol_name = file_results["protocol"]["metadata"].get("protocolName", "") + if "Ramp Rate" in protocol_name: + ip = filename.split("_")[0] + if len(ramp_rates) > 1: + cooling_ramp_rate = abs(min(ramp_rates.values())) + heating_ramp_rate = abs(max(ramp_rates.values())) + start_time = datetime.strptime( + file_results.get("startedAt", ""), "%Y-%m-%dT%H:%M:%S.%f%z" + ) + start_date = str(start_time.date()) + module_serial_number = file_results["modules"][0].get( + "serialNumber", "NaN" + ) + try: + response = requests.get( + f"http://{ip}:31950/modules", + headers={"opentrons-version": "3"}, + ) + modules = response.json() + for module in modules["data"]: + if module["serialNumber"] == module_serial_number: + firmwareVersion = module["firmwareVersion"] + else: + firmwareVersion = "NaN" + except requests.exceptions.ConnectionError: + firmwareVersion = "NaN" + row = { + "Robot": file_results.get("robot_name", ""), + "Run_ID": run_id, + "Protocol_Name": file_results["protocol"]["metadata"].get( + "protocolName", "" + ), + "Software Version": file_results.get("API_Version", ""), + "Firmware Version": firmwareVersion, + "Date": start_date, + "Serial Number": module_serial_number, + "Approx. Average Heating Ramp Rate (C/s)": heating_ramp_rate, + "Approx. Average Cooling Ramp Rate (C/s)": cooling_ramp_rate, + } + headers = list(row.keys()) + runs_and_robots[run_id] = row + read_robot_logs.write_to_local_and_google_sheet( + runs_and_robots, + storage_directory, + google_sheet_name, + google_sheet, + headers, + ) + else: + continue diff --git a/abr-testing/abr_testing/data_collection/read_robot_logs.py b/abr-testing/abr_testing/data_collection/read_robot_logs.py index 48ef1d20163..7539e913057 100644 --- a/abr-testing/abr_testing/data_collection/read_robot_logs.py +++ b/abr-testing/abr_testing/data_collection/read_robot_logs.py @@ -12,6 +12,7 @@ import time as t import json import requests +import sys def lpc_data(file_results: Dict[str, Any], protocol_info: Dict) -> List[Dict[str, Any]]: @@ -72,9 +73,10 @@ def hs_commands(file_results: Dict[str, Any]) -> Dict[str, float]: hs_home_count: float = 0.0 hs_speed: float = 0.0 hs_rotations: Dict[str, float] = dict() - hs_temps: Dict[str, float] = dict() + hs_temps: Dict[float, float] = dict() temp_time = None shake_time = None + deactivate_time = None for command in commandData: commandType = command["commandType"] # Heatershaker @@ -87,17 +89,21 @@ def hs_commands(file_results: Dict[str, Any]) -> Dict[str, float]: # Home count elif commandType == "heaterShaker/deactivateShaker": hs_home_count += 1 + shake_deactivate_time = datetime.strptime( + command.get("startedAt", ""), "%Y-%m-%dT%H:%M:%S.%f%z" + ) + if shake_time is not None and shake_deactivate_time > shake_time: + shake_duration = (shake_deactivate_time - shake_time).total_seconds() + hs_rotations[hs_speed] = hs_rotations.get(hs_speed, 0.0) + ( + (hs_speed * shake_duration) / 60 + ) + elif commandType == "heaterShaker/deactivateHeater": deactivate_time = datetime.strptime( command.get("startedAt", ""), "%Y-%m-%dT%H:%M:%S.%f%z" ) if temp_time is not None and deactivate_time > temp_time: temp_duration = (deactivate_time - temp_time).total_seconds() hs_temps[hs_temp] = hs_temps.get(hs_temp, 0.0) + temp_duration - if shake_time is not None and deactivate_time > shake_time: - shake_duration = (deactivate_time - shake_time).total_seconds() - hs_rotations[hs_speed] = hs_rotations.get(hs_speed, 0.0) + ( - (hs_speed * shake_duration) / 60 - ) # of Rotations elif commandType == "heaterShaker/setAndWaitForShakeSpeed": hs_speed = command["params"]["rpm"] @@ -111,6 +117,13 @@ def hs_commands(file_results: Dict[str, Any]) -> Dict[str, float]: temp_time = datetime.strptime( command.get("completedAt", ""), "%Y-%m-%dT%H:%M:%S.%f%z" ) + if temp_time is not None and deactivate_time is None: + # If heater shaker module is not deactivated, protocol completedAt time stamp used. + protocol_end = datetime.strptime( + file_results.get("completedAt", ""), "%Y-%m-%dT%H:%M:%S.%f%z" + ) + temp_duration = (protocol_end - temp_time).total_seconds() + hs_temps[hs_temp] = hs_temps.get(hs_temp, 0.0) + temp_duration hs_latch_sets = hs_latch_count / 2 # one set of open/close hs_total_rotations = sum(hs_rotations.values()) hs_total_temp_time = sum(hs_temps.values()) @@ -254,7 +267,7 @@ def create_abr_data_sheet( file_name_csv = file_name + ".csv" sheet_location = os.path.join(storage_directory, file_name_csv) if os.path.exists(sheet_location): - print(f"File {sheet_location} located. Not overwriting.") + return sheet_location else: with open(sheet_location, "w") as csvfile: writer = csv.DictWriter(csvfile, fieldnames=headers) @@ -286,11 +299,10 @@ def get_error_info(file_results: Dict[str, Any]) -> Tuple[int, str, str, str, st # Instrument Error error_instrument = run_command_error["error"]["errorInfo"]["node"] except KeyError: - # Module Error + # Module error_instrument = run_command_error["error"]["errorInfo"].get("port", "") else: error_type = file_results["errors"][0]["errorType"] - print(error_type) error_code = file_results["errors"][0]["errorCode"] error_instrument = file_results["errors"][0]["detail"] for error in error_levels: @@ -368,7 +380,6 @@ def get_run_ids_from_storage(storage_directory: str) -> Set[str]: def get_unseen_run_ids(runs: Set[str], runs_from_storage: Set[str]) -> Set[str]: """Subtracts runs from storage from current runs being read.""" runs_to_save = runs - runs_from_storage - print(f"There are {str(len(runs_to_save))} new run(s) to save.") return runs_to_save @@ -406,7 +417,7 @@ def write_to_sheets( google_sheet.write_header(headers) google_sheet.update_row_index() google_sheet.write_to_row(row_list) - t.sleep(5) # Sleep added to avoid API error. + t.sleep(5) def get_calibration_offsets( @@ -415,9 +426,14 @@ def get_calibration_offsets( """Connect to robot via ip and get calibration data.""" calibration = dict() # Robot Information [Name, Software Version] - response = requests.get( - f"http://{ip}:31950/health", headers={"opentrons-version": "3"} - ) + try: + response = requests.get( + f"http://{ip}:31950/health", headers={"opentrons-version": "3"} + ) + print(f"Connected to {ip}") + except Exception: + print(f"ERROR: Failed to read IP address: {ip}") + sys.exit() health_data = response.json() robot_name = health_data.get("name", "") api_version = health_data.get("api_version", "") diff --git a/abr-testing/abr_testing/data_collection/single_run_log_reader.py b/abr-testing/abr_testing/data_collection/single_run_log_reader.py new file mode 100644 index 00000000000..df078929338 --- /dev/null +++ b/abr-testing/abr_testing/data_collection/single_run_log_reader.py @@ -0,0 +1,51 @@ +"""Reads single run log retrieved by get_run_logs.py and saves to local csv.""" +import argparse +import sys +import os +import csv +from abr_testing.data_collection import read_robot_logs +from abr_testing.data_collection import abr_google_drive + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Read single run log locally saved.") + parser.add_argument( + "run_log_file_path", + metavar="RUN_LOG_FILE_PATH", + type=str, + nargs=1, + help="Folder path that holds individual run logs of interest.", + ) + parser.add_argument( + "google_sheet_name", + metavar="GOOGLE_SHEET_NAME", + type=str, + nargs=1, + help="Google sheet name.", + ) + args = parser.parse_args() + run_log_file_path = args.run_log_file_path[0] + google_sheet_name = args.google_sheet_name[0] + + try: + credentials_path = os.path.join(run_log_file_path, "credentials.json") + except FileNotFoundError: + print(f"Add credentials.json file to: {run_log_file_path}.") + sys.exit() + # Get Runs from Storage and Read Logs + run_ids_in_storage = read_robot_logs.get_run_ids_from_storage(run_log_file_path) + runs_and_robots, header = abr_google_drive.create_data_dictionary( + run_ids_in_storage, run_log_file_path, "" + ) + list_of_runs = list(runs_and_robots.keys()) + # Adds Run to local csv + sheet_location = os.path.join(run_log_file_path, "saved_data.csv") + file_exists = os.path.exists(sheet_location) and os.path.getsize(sheet_location) > 0 + with open(sheet_location, "a", newline="") as f: + writer = csv.writer(f) + if not file_exists: + writer.writerow(header) + for run in list_of_runs: + # Add new row + row = runs_and_robots[run].values() + row_list = list(row) + writer.writerow(row_list) diff --git a/abr-testing/abr_testing/tools/abr_scale.py b/abr-testing/abr_testing/tools/abr_scale.py index 75c887d4ecc..d916c64c0d4 100644 --- a/abr-testing/abr_testing/tools/abr_scale.py +++ b/abr-testing/abr_testing/tools/abr_scale.py @@ -25,25 +25,7 @@ nargs=1, help="Name of google sheet and local csv to save data to.", ) - parser.add_argument("robot", metavar="ROBOT", type=str, nargs=1, help="Robot name.") - parser.add_argument( - "labware_name", - metavar="LABWARE_NAME", - type=str, - nargs=1, - help="Name of labware.", - ) - parser.add_argument( - "protocol_step", - metavar="PROTOCOL_STEP", - type=str, - nargs=1, - help="1 for empty plate, 2 for filled plate, 3 for end of protocol.", - ) args = parser.parse_args() - robot = args.robot[0] - labware = args.labware_name[0] - protocol_step = args.protocol_step[0] storage_directory = args.storage_directory[0] file_name = args.file_name[0] file_name_csv = file_name + ".csv" @@ -71,7 +53,9 @@ print("Connected to google sheet.") except FileNotFoundError: print("No google sheets credentials. Add credentials to storage notebook.") - + robot = input("Robot: ") + labware = input("Labware: ") + protocol_step = input("Measurement Step (1,2,3): ") # Scale Loop grams, is_stable = scale.read_mass() grams, is_stable = scale.read_mass() diff --git a/abr-testing/abr_testing/tools/query_and_download.py b/abr-testing/abr_testing/tools/query_and_download.py new file mode 100644 index 00000000000..320b99b333e --- /dev/null +++ b/abr-testing/abr_testing/tools/query_and_download.py @@ -0,0 +1,48 @@ +"""Download files from google drive based off string search.""" +from abr_testing.automation import google_drive_tool +import argparse +import os +import json +import sys + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Download files based off title search." + ) + parser.add_argument( + "storage_directory", + metavar="STORAGE_DIRECTORY", + type=str, + nargs=1, + help="Path save downloaded files. Contains .json file with query words.", + ) + parser.add_argument( + "folder_name", + metavar="FOLDER_NAME", + type=str, + nargs=1, + help="Google Drive folder name. Open desired folder and copy string after drive/folders/.", + ) + parser.add_argument( + "email", metavar="EMAIL", type=str, nargs=1, help="opentrons gmail." + ) + args = parser.parse_args() + folder_name = args.folder_name[0] + email = args.email[0] + storage_directory = args.storage_directory[0] + + search_file_path = os.path.join(storage_directory, "search_words.json") + try: + search_file = json.load(open(search_file_path)) + except FileNotFoundError: + print("Add .json file with search words formatted in a list.") + try: + credentials_path = os.path.join(storage_directory, "credentials.json") + except FileNotFoundError: + print(f"Add credentials.json file to: {storage_directory}.") + sys.exit() + google_drive = google_drive_tool.google_drive(credentials_path, folder_name, email) + print("Connected to google drive.") + search_lists = search_file["search_words"] + found_files = google_drive.search_folder(search_lists, folder_name) + google_drive.download_files(found_files, storage_directory) diff --git a/api-client/src/protocols/__fixtures__/simpleAnalysisFile.json b/api-client/src/protocols/__fixtures__/simpleAnalysisFile.json index 74faa60fcb6..bb6aacccd6e 100644 --- a/api-client/src/protocols/__fixtures__/simpleAnalysisFile.json +++ b/api-client/src/protocols/__fixtures__/simpleAnalysisFile.json @@ -3989,5 +3989,6 @@ } ] } - ] + ], + "robotType": "OT-2 Standard" } diff --git a/api-client/src/protocols/createProtocol.ts b/api-client/src/protocols/createProtocol.ts index 2bcbefe6a7b..a4f9961b9c9 100644 --- a/api-client/src/protocols/createProtocol.ts +++ b/api-client/src/protocols/createProtocol.ts @@ -11,7 +11,9 @@ export function createProtocol( runTimeParameterValues?: RunTimeParameterCreateData ): ResponsePromise { const formData = new FormData() - files.forEach(file => formData.append('files', file, file.name)) + files.forEach(file => { + formData.append('files', file, file.name) + }) if (protocolKey != null) formData.append('key', protocolKey) if (runTimeParameterValues != null) formData.append( diff --git a/api-client/src/protocols/createProtocolAnalysis.ts b/api-client/src/protocols/createProtocolAnalysis.ts new file mode 100644 index 00000000000..81ab83c11af --- /dev/null +++ b/api-client/src/protocols/createProtocolAnalysis.ts @@ -0,0 +1,28 @@ +import { POST, request } from '../request' + +import type { ProtocolAnalysisSummary } from '@opentrons/shared-data' +import type { ResponsePromise } from '../request' +import type { HostConfig } from '../types' +import type { RunTimeParameterCreateData } from '../runs' + +interface CreateProtocolAnalysisData { + runTimeParameterValues: RunTimeParameterCreateData + forceReAnalyze: boolean +} + +export function createProtocolAnalysis( + config: HostConfig, + protocolKey: string, + runTimeParameterValues?: RunTimeParameterCreateData, + forceReAnalyze?: boolean +): ResponsePromise { + const data = { + runTimeParameterValues: runTimeParameterValues ?? {}, + forceReAnalyze: forceReAnalyze ?? false, + } + const response = request< + ProtocolAnalysisSummary[], + { data: CreateProtocolAnalysisData } + >(POST, `/protocols/${protocolKey}/analyses`, { data }, config) + return response +} diff --git a/api-client/src/protocols/index.ts b/api-client/src/protocols/index.ts index 6febd0795cf..f035fa000e1 100644 --- a/api-client/src/protocols/index.ts +++ b/api-client/src/protocols/index.ts @@ -3,6 +3,7 @@ export { getProtocolAnalyses } from './getProtocolAnalyses' export { getProtocolAnalysisAsDocument } from './getProtocolAnalysisAsDocument' export { deleteProtocol } from './deleteProtocol' export { createProtocol } from './createProtocol' +export { createProtocolAnalysis } from './createProtocolAnalysis' export { getProtocols } from './getProtocols' export { getProtocolIds } from './getProtocolIds' diff --git a/api-client/src/robot/getRobotSettings.ts b/api-client/src/robot/getRobotSettings.ts new file mode 100644 index 00000000000..ffe0014fcb0 --- /dev/null +++ b/api-client/src/robot/getRobotSettings.ts @@ -0,0 +1,11 @@ +import { GET, request } from '../request' + +import type { ResponsePromise } from '../request' +import type { HostConfig } from '../types' +import type { RobotSettingsResponse } from './types' + +export function getRobotSettings( + config: HostConfig +): ResponsePromise { + return request(GET, '/settings', null, config) +} diff --git a/api-client/src/robot/index.ts b/api-client/src/robot/index.ts index 96ef28165b0..55052d7b7c8 100644 --- a/api-client/src/robot/index.ts +++ b/api-client/src/robot/index.ts @@ -3,11 +3,18 @@ export { getEstopStatus } from './getEstopStatus' export { acknowledgeEstopDisengage } from './acknowledgeEstopDisengage' export { getLights } from './getLights' export { setLights } from './setLights' +export { getRobotSettings } from './getRobotSettings' +export { updateRobotSetting } from './updateRobotSetting' + export type { DoorStatus, EstopPhysicalStatus, EstopState, EstopStatus, Lights, + RobotSettings, + RobotSettingsField, + RobotSettingsResponse, SetLightsData, + UpdateRobotSettingRequest, } from './types' diff --git a/api-client/src/robot/types.ts b/api-client/src/robot/types.ts index 00d887b9c4e..41ef7f1281e 100644 --- a/api-client/src/robot/types.ts +++ b/api-client/src/robot/types.ts @@ -27,3 +27,23 @@ export interface Lights { export interface SetLightsData { on: boolean } + +export interface RobotSettingsField { + id: string + title: string + description: string + value: boolean | null + restart_required?: boolean +} + +export type RobotSettings = RobotSettingsField[] + +export interface UpdateRobotSettingRequest { + id: string + value: boolean | null +} + +export interface RobotSettingsResponse { + settings: RobotSettings + links?: { restart?: string } +} diff --git a/api-client/src/robot/updateRobotSetting.ts b/api-client/src/robot/updateRobotSetting.ts new file mode 100644 index 00000000000..a5775abaeee --- /dev/null +++ b/api-client/src/robot/updateRobotSetting.ts @@ -0,0 +1,18 @@ +import { POST, request } from '../request' + +import type { ResponsePromise } from '../request' +import type { HostConfig } from '../types' +import type { RobotSettingsResponse, UpdateRobotSettingRequest } from './types' + +export function updateRobotSetting( + config: HostConfig, + id: string, + value: boolean +): ResponsePromise { + return request( + POST, + '/settings', + { id, value }, + config + ) +} diff --git a/api-client/src/runs/commands/getCommandsAsPreSerializedList.ts b/api-client/src/runs/commands/getCommandsAsPreSerializedList.ts new file mode 100644 index 00000000000..420f984b280 --- /dev/null +++ b/api-client/src/runs/commands/getCommandsAsPreSerializedList.ts @@ -0,0 +1,22 @@ +import { GET, request } from '../../request' + +import type { ResponsePromise } from '../../request' +import type { HostConfig } from '../../types' +import type { + CommandsAsPreSerializedListData, + GetCommandsParams, +} from './types' + +export function getCommandsAsPreSerializedList( + config: HostConfig, + runId: string, + params: GetCommandsParams +): ResponsePromise { + return request( + GET, + `/runs/${runId}/commandsAsPreSerializedList`, + null, + config, + params + ) +} diff --git a/api-client/src/runs/commands/types.ts b/api-client/src/runs/commands/types.ts index acea40e1880..d0b443b297a 100644 --- a/api-client/src/runs/commands/types.ts +++ b/api-client/src/runs/commands/types.ts @@ -34,6 +34,12 @@ export interface CommandsData { links: CommandsLinks } +export interface CommandsAsPreSerializedListData { + data: string[] + meta: GetCommandsParams & { totalLength: number } + links: CommandsLinks +} + export interface CreateCommandParams { waitUntilComplete?: boolean timeout?: number diff --git a/api-client/src/runs/constants.ts b/api-client/src/runs/constants.ts new file mode 100644 index 00000000000..9f0d8293ef6 --- /dev/null +++ b/api-client/src/runs/constants.ts @@ -0,0 +1,11 @@ +import { + RUN_STATUS_FAILED, + RUN_STATUS_STOPPED, + RUN_STATUS_SUCCEEDED, +} from './types' + +export const RUN_STATUSES_TERMINAL = [ + RUN_STATUS_SUCCEEDED, + RUN_STATUS_FAILED, + RUN_STATUS_STOPPED, +] diff --git a/api-client/src/runs/index.ts b/api-client/src/runs/index.ts index fa38dade02f..01653713c81 100644 --- a/api-client/src/runs/index.ts +++ b/api-client/src/runs/index.ts @@ -7,9 +7,10 @@ export { createCommand } from './commands/createCommand' export { createLiveCommand } from './commands/createLiveCommand' export { getCommand } from './commands/getCommand' export { getCommands } from './commands/getCommands' +export { getCommandsAsPreSerializedList } from './commands/getCommandsAsPreSerializedList' export { createRunAction } from './createRunAction' export * from './createLabwareOffset' export * from './createLabwareDefinition' - +export * from './constants' export * from './types' export type { CreateRunData } from './createRun' diff --git a/api-client/src/runs/types.ts b/api-client/src/runs/types.ts index 7e6ec2b0ee7..36c5f9a3a20 100644 --- a/api-client/src/runs/types.ts +++ b/api-client/src/runs/types.ts @@ -4,6 +4,7 @@ import type { LoadedPipette, ModuleModel, RunTimeCommand, + RunTimeParameter, } from '@opentrons/shared-data' import type { ResourceLink, ErrorDetails } from '../types' export * from './commands/types' @@ -47,7 +48,7 @@ export interface LegacyGoodRunData { modules: LoadedModule[] protocolId?: string labwareOffsets?: LabwareOffset[] - runTimeParameterValues?: RunTimeParameterCreateData + runTimeParameters: RunTimeParameter[] } export interface KnownGoodRunData extends LegacyGoodRunData { diff --git a/api-client/src/subsystems/types.ts b/api-client/src/subsystems/types.ts index 14f45324f62..564d59b21b2 100644 --- a/api-client/src/subsystems/types.ts +++ b/api-client/src/subsystems/types.ts @@ -6,6 +6,7 @@ export type Subsystem = | 'pipette_right' | 'gripper' | 'rear_panel' + | 'hepa_uv' type UpdateStatus = 'queued' | 'updating' | 'done' export interface SubsystemUpdateProgressData { diff --git a/api-client/src/system/__tests__/utils.test.ts b/api-client/src/system/__tests__/utils.test.ts new file mode 100644 index 00000000000..3121c061a59 --- /dev/null +++ b/api-client/src/system/__tests__/utils.test.ts @@ -0,0 +1,20 @@ +import { describe, expect, it } from 'vitest' +import { sanitizeFileName } from '../utils' + +describe('sanitizeFileName', () => { + it('returns original alphanumeric file name', () => { + expect(sanitizeFileName('an0ther_otie_logo.png')).toEqual( + 'an0ther_otie_logo.png' + ) + }) + + it('sanitizes a file name', () => { + expect( + sanitizeFileName( + `otie's birthday/party - (& the bouncy castle cost ~$100,000).jpeg` + ) + ).toEqual( + 'otie_s_birthday_party_-____the_bouncy_castle_cost___100_000_.jpeg' + ) + }) +}) diff --git a/api-client/src/system/createSplash.ts b/api-client/src/system/createSplash.ts new file mode 100644 index 00000000000..abaa280b226 --- /dev/null +++ b/api-client/src/system/createSplash.ts @@ -0,0 +1,26 @@ +import { POST, request } from '../request' +import { sanitizeFileName } from './utils' +import type { ResponsePromise } from '../request' +import type { HostConfig } from '../types' + +export function createSplash( + config: HostConfig, + file: File +): ResponsePromise { + // sanitize file name to ensure no spaces or special characters + const newFileName = sanitizeFileName(file.name) + const renamedFile = new File([file], newFileName, { + type: 'image/png', + }) + + const formData = new FormData() + formData.append('file', renamedFile) + + // eslint-disable-next-line @typescript-eslint/no-invalid-void-type + return request( + POST, + '/system/oem_mode/upload_splash', + formData, + config + ) +} diff --git a/api-client/src/system/index.ts b/api-client/src/system/index.ts index 025a303a5b5..4dc86594d2c 100644 --- a/api-client/src/system/index.ts +++ b/api-client/src/system/index.ts @@ -1,4 +1,6 @@ export { createAuthorization } from './createAuthorization' export { createRegistration } from './createRegistration' +export { createSplash } from './createSplash' export { getConnections } from './getConnections' export * from './types' +export * from './utils' diff --git a/api-client/src/system/utils.ts b/api-client/src/system/utils.ts new file mode 100644 index 00000000000..cc0eea11130 --- /dev/null +++ b/api-client/src/system/utils.ts @@ -0,0 +1,3 @@ +export function sanitizeFileName(fileName: string): string { + return fileName.replace(/[^a-zA-Z0-9-.]/gi, '_') +} diff --git a/api/Pipfile b/api/Pipfile index 710a5cb6f22..7be11b82934 100755 --- a/api/Pipfile +++ b/api/Pipfile @@ -48,3 +48,4 @@ pytest-profiling = "~=1.7.0" # TODO(mc, 2022-03-31): upgrade sphinx, remove this subdep pin jinja2 = ">=2.3,<3.1" hypothesis = "==6.96.1" +performance-metrics = {file = "../performance-metrics", editable = true} diff --git a/api/Pipfile.lock b/api/Pipfile.lock index cc9f3163e51..94643ce22a7 100644 --- a/api/Pipfile.lock +++ b/api/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "f0d4979ecb4f125cef848e0ce31e3a5e9cded69abaf773ad90d00016f6d2a65d" + "sha256": "a531665bfd7452ea19565ee95137118966532a8ab5475b7d5ee086ada333e627" }, "pipfile-spec": 6, "requires": {}, @@ -56,11 +56,11 @@ }, "idna": { "hashes": [ - "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", - "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" + "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", + "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" ], "markers": "python_version >= '3.5'", - "version": "==3.6" + "version": "==3.7" }, "jsonschema": { "hashes": [ @@ -73,65 +73,65 @@ }, "msgpack": { "hashes": [ - "sha256:04ad6069c86e531682f9e1e71b71c1c3937d6014a7c3e9edd2aa81ad58842862", - "sha256:0bfdd914e55e0d2c9e1526de210f6fe8ffe9705f2b1dfcc4aecc92a4cb4b533d", - "sha256:1dc93e8e4653bdb5910aed79f11e165c85732067614f180f70534f056da97db3", - "sha256:1e2d69948e4132813b8d1131f29f9101bc2c915f26089a6d632001a5c1349672", - "sha256:235a31ec7db685f5c82233bddf9858748b89b8119bf4538d514536c485c15fe0", - "sha256:27dcd6f46a21c18fa5e5deed92a43d4554e3df8d8ca5a47bf0615d6a5f39dbc9", - "sha256:28efb066cde83c479dfe5a48141a53bc7e5f13f785b92ddde336c716663039ee", - "sha256:3476fae43db72bd11f29a5147ae2f3cb22e2f1a91d575ef130d2bf49afd21c46", - "sha256:36e17c4592231a7dbd2ed09027823ab295d2791b3b1efb2aee874b10548b7524", - "sha256:384d779f0d6f1b110eae74cb0659d9aa6ff35aaf547b3955abf2ab4c901c4819", - "sha256:38949d30b11ae5f95c3c91917ee7a6b239f5ec276f271f28638dec9156f82cfc", - "sha256:3967e4ad1aa9da62fd53e346ed17d7b2e922cba5ab93bdd46febcac39be636fc", - "sha256:3e7bf4442b310ff154b7bb9d81eb2c016b7d597e364f97d72b1acc3817a0fdc1", - "sha256:3f0c8c6dfa6605ab8ff0611995ee30d4f9fcff89966cf562733b4008a3d60d82", - "sha256:484ae3240666ad34cfa31eea7b8c6cd2f1fdaae21d73ce2974211df099a95d81", - "sha256:4a7b4f35de6a304b5533c238bee86b670b75b03d31b7797929caa7a624b5dda6", - "sha256:4cb14ce54d9b857be9591ac364cb08dc2d6a5c4318c1182cb1d02274029d590d", - "sha256:4e71bc4416de195d6e9b4ee93ad3f2f6b2ce11d042b4d7a7ee00bbe0358bd0c2", - "sha256:52700dc63a4676669b341ba33520f4d6e43d3ca58d422e22ba66d1736b0a6e4c", - "sha256:572efc93db7a4d27e404501975ca6d2d9775705c2d922390d878fcf768d92c87", - "sha256:576eb384292b139821c41995523654ad82d1916da6a60cff129c715a6223ea84", - "sha256:5b0bf0effb196ed76b7ad883848143427a73c355ae8e569fa538365064188b8e", - "sha256:5b6ccc0c85916998d788b295765ea0e9cb9aac7e4a8ed71d12e7d8ac31c23c95", - "sha256:5ed82f5a7af3697b1c4786053736f24a0efd0a1b8a130d4c7bfee4b9ded0f08f", - "sha256:6d4c80667de2e36970ebf74f42d1088cc9ee7ef5f4e8c35eee1b40eafd33ca5b", - "sha256:730076207cb816138cf1af7f7237b208340a2c5e749707457d70705715c93b93", - "sha256:7687e22a31e976a0e7fc99c2f4d11ca45eff652a81eb8c8085e9609298916dcf", - "sha256:822ea70dc4018c7e6223f13affd1c5c30c0f5c12ac1f96cd8e9949acddb48a61", - "sha256:84b0daf226913133f899ea9b30618722d45feffa67e4fe867b0b5ae83a34060c", - "sha256:85765fdf4b27eb5086f05ac0491090fc76f4f2b28e09d9350c31aac25a5aaff8", - "sha256:8dd178c4c80706546702c59529ffc005681bd6dc2ea234c450661b205445a34d", - "sha256:8f5b234f567cf76ee489502ceb7165c2a5cecec081db2b37e35332b537f8157c", - "sha256:98bbd754a422a0b123c66a4c341de0474cad4a5c10c164ceed6ea090f3563db4", - "sha256:993584fc821c58d5993521bfdcd31a4adf025c7d745bbd4d12ccfecf695af5ba", - "sha256:a40821a89dc373d6427e2b44b572efc36a2778d3f543299e2f24eb1a5de65415", - "sha256:b291f0ee7961a597cbbcc77709374087fa2a9afe7bdb6a40dbbd9b127e79afee", - "sha256:b573a43ef7c368ba4ea06050a957c2a7550f729c31f11dd616d2ac4aba99888d", - "sha256:b610ff0f24e9f11c9ae653c67ff8cc03c075131401b3e5ef4b82570d1728f8a9", - "sha256:bdf38ba2d393c7911ae989c3bbba510ebbcdf4ecbdbfec36272abe350c454075", - "sha256:bfef2bb6ef068827bbd021017a107194956918ab43ce4d6dc945ffa13efbc25f", - "sha256:cab3db8bab4b7e635c1c97270d7a4b2a90c070b33cbc00c99ef3f9be03d3e1f7", - "sha256:cb70766519500281815dfd7a87d3a178acf7ce95390544b8c90587d76b227681", - "sha256:cca1b62fe70d761a282496b96a5e51c44c213e410a964bdffe0928e611368329", - "sha256:ccf9a39706b604d884d2cb1e27fe973bc55f2890c52f38df742bc1d79ab9f5e1", - "sha256:dc43f1ec66eb8440567186ae2f8c447d91e0372d793dfe8c222aec857b81a8cf", - "sha256:dd632777ff3beaaf629f1ab4396caf7ba0bdd075d948a69460d13d44357aca4c", - "sha256:e45ae4927759289c30ccba8d9fdce62bb414977ba158286b5ddaf8df2cddb5c5", - "sha256:e50ebce52f41370707f1e21a59514e3375e3edd6e1832f5e5235237db933c98b", - "sha256:ebbbba226f0a108a7366bf4b59bf0f30a12fd5e75100c630267d94d7f0ad20e5", - "sha256:ec79ff6159dffcc30853b2ad612ed572af86c92b5168aa3fc01a67b0fa40665e", - "sha256:f0936e08e0003f66bfd97e74ee530427707297b0d0361247e9b4f59ab78ddc8b", - "sha256:f26a07a6e877c76a88e3cecac8531908d980d3d5067ff69213653649ec0f60ad", - "sha256:f64e376cd20d3f030190e8c32e1c64582eba56ac6dc7d5b0b49a9d44021b52fd", - "sha256:f6ffbc252eb0d229aeb2f9ad051200668fc3a9aaa8994e49f0cb2ffe2b7867e7", - "sha256:f9a7c509542db4eceed3dcf21ee5267ab565a83555c9b88a8109dcecc4709002", - "sha256:ff1d0899f104f3921d94579a5638847f783c9b04f2d5f229392ca77fba5b82fc" + "sha256:00e073efcba9ea99db5acef3959efa45b52bc67b61b00823d2a1a6944bf45982", + "sha256:0726c282d188e204281ebd8de31724b7d749adebc086873a59efb8cf7ae27df3", + "sha256:0ceea77719d45c839fd73abcb190b8390412a890df2f83fb8cf49b2a4b5c2f40", + "sha256:114be227f5213ef8b215c22dde19532f5da9652e56e8ce969bf0a26d7c419fee", + "sha256:13577ec9e247f8741c84d06b9ece5f654920d8365a4b636ce0e44f15e07ec693", + "sha256:1876b0b653a808fcd50123b953af170c535027bf1d053b59790eebb0aeb38950", + "sha256:1ab0bbcd4d1f7b6991ee7c753655b481c50084294218de69365f8f1970d4c151", + "sha256:1cce488457370ffd1f953846f82323cb6b2ad2190987cd4d70b2713e17268d24", + "sha256:26ee97a8261e6e35885c2ecd2fd4a6d38252246f94a2aec23665a4e66d066305", + "sha256:3528807cbbb7f315bb81959d5961855e7ba52aa60a3097151cb21956fbc7502b", + "sha256:374a8e88ddab84b9ada695d255679fb99c53513c0a51778796fcf0944d6c789c", + "sha256:376081f471a2ef24828b83a641a02c575d6103a3ad7fd7dade5486cad10ea659", + "sha256:3923a1778f7e5ef31865893fdca12a8d7dc03a44b33e2a5f3295416314c09f5d", + "sha256:4916727e31c28be8beaf11cf117d6f6f188dcc36daae4e851fee88646f5b6b18", + "sha256:493c5c5e44b06d6c9268ce21b302c9ca055c1fd3484c25ba41d34476c76ee746", + "sha256:505fe3d03856ac7d215dbe005414bc28505d26f0c128906037e66d98c4e95868", + "sha256:5845fdf5e5d5b78a49b826fcdc0eb2e2aa7191980e3d2cfd2a30303a74f212e2", + "sha256:5c330eace3dd100bdb54b5653b966de7f51c26ec4a7d4e87132d9b4f738220ba", + "sha256:5dbf059fb4b7c240c873c1245ee112505be27497e90f7c6591261c7d3c3a8228", + "sha256:5e390971d082dba073c05dbd56322427d3280b7cc8b53484c9377adfbae67dc2", + "sha256:5fbb160554e319f7b22ecf530a80a3ff496d38e8e07ae763b9e82fadfe96f273", + "sha256:64d0fcd436c5683fdd7c907eeae5e2cbb5eb872fafbc03a43609d7941840995c", + "sha256:69284049d07fce531c17404fcba2bb1df472bc2dcdac642ae71a2d079d950653", + "sha256:6a0e76621f6e1f908ae52860bdcb58e1ca85231a9b0545e64509c931dd34275a", + "sha256:73ee792784d48aa338bba28063e19a27e8d989344f34aad14ea6e1b9bd83f596", + "sha256:74398a4cf19de42e1498368c36eed45d9528f5fd0155241e82c4082b7e16cffd", + "sha256:7938111ed1358f536daf311be244f34df7bf3cdedb3ed883787aca97778b28d8", + "sha256:82d92c773fbc6942a7a8b520d22c11cfc8fd83bba86116bfcf962c2f5c2ecdaa", + "sha256:83b5c044f3eff2a6534768ccfd50425939e7a8b5cf9a7261c385de1e20dcfc85", + "sha256:8db8e423192303ed77cff4dce3a4b88dbfaf43979d280181558af5e2c3c71afc", + "sha256:9517004e21664f2b5a5fd6333b0731b9cf0817403a941b393d89a2f1dc2bd836", + "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3", + "sha256:99881222f4a8c2f641f25703963a5cefb076adffd959e0558dc9f803a52d6a58", + "sha256:9ee32dcb8e531adae1f1ca568822e9b3a738369b3b686d1477cbc643c4a9c128", + "sha256:a22e47578b30a3e199ab067a4d43d790249b3c0587d9a771921f86250c8435db", + "sha256:b5505774ea2a73a86ea176e8a9a4a7c8bf5d521050f0f6f8426afe798689243f", + "sha256:bd739c9251d01e0279ce729e37b39d49a08c0420d3fee7f2a4968c0576678f77", + "sha256:d16a786905034e7e34098634b184a7d81f91d4c3d246edc6bd7aefb2fd8ea6ad", + "sha256:d3420522057ebab1728b21ad473aa950026d07cb09da41103f8e597dfbfaeb13", + "sha256:d56fd9f1f1cdc8227d7b7918f55091349741904d9520c65f0139a9755952c9e8", + "sha256:d661dc4785affa9d0edfdd1e59ec056a58b3dbb9f196fa43587f3ddac654ac7b", + "sha256:dfe1f0f0ed5785c187144c46a292b8c34c1295c01da12e10ccddfc16def4448a", + "sha256:e1dd7839443592d00e96db831eddb4111a2a81a46b028f0facd60a09ebbdd543", + "sha256:e2872993e209f7ed04d963e4b4fbae72d034844ec66bc4ca403329db2074377b", + "sha256:e2f879ab92ce502a1e65fce390eab619774dda6a6ff719718069ac94084098ce", + "sha256:e3aa7e51d738e0ec0afbed661261513b38b3014754c9459508399baf14ae0c9d", + "sha256:e532dbd6ddfe13946de050d7474e3f5fb6ec774fbb1a188aaf469b08cf04189a", + "sha256:e6b7842518a63a9f17107eb176320960ec095a8ee3b4420b5f688e24bf50c53c", + "sha256:e75753aeda0ddc4c28dce4c32ba2f6ec30b1b02f6c0b14e547841ba5b24f753f", + "sha256:eadb9f826c138e6cf3c49d6f8de88225a3c0ab181a9b4ba792e006e5292d150e", + "sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011", + "sha256:ef254a06bcea461e65ff0373d8a0dd1ed3aa004af48839f002a0c994a6f72d04", + "sha256:f3709997b228685fe53e8c433e2df9f0cdb5f4542bd5114ed17ac3c0129b0480", + "sha256:f51bab98d52739c50c56658cc303f190785f9a2cd97b823357e7aeae54c8f68a", + "sha256:f9904e24646570539a8950400602d66d2b2c492b9010ea7e965025cb71d0c86d", + "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d" ], "markers": "platform_system != 'Windows'", - "version": "==1.0.7" + "version": "==1.0.8" }, "numpy": { "hashes": [ @@ -162,6 +162,7 @@ }, "opentrons": { "editable": true, + "markers": "python_version >= '3.8'", "path": "." }, "opentrons-hardware": { @@ -173,15 +174,16 @@ }, "opentrons-shared-data": { "editable": true, + "markers": "python_version >= '3.8'", "path": "../shared-data/python" }, "packaging": { "hashes": [ - "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", - "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" + "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", + "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9" ], "markers": "python_version >= '3.7'", - "version": "==23.2" + "version": "==24.0" }, "pydantic": { "hashes": [ @@ -276,32 +278,31 @@ "sha256:6ad50f4613289f3c4d276b6d2ac8901d776dcb929994cce93f55a69e858c595f", "sha256:7eea9b81b0ff908000a825db024313f622895bd578e8a17433e0474cd7d2da83" ], - "markers": "python_version >= '3.7'", "version": "==4.2.2" }, "setuptools": { "hashes": [ - "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05", - "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78" + "sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987", + "sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32" ], "markers": "python_version >= '3.8'", - "version": "==69.0.3" + "version": "==69.5.1" }, "sniffio": { "hashes": [ - "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101", - "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384" + "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", + "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" ], "markers": "python_version >= '3.7'", - "version": "==1.3.0" + "version": "==1.3.1" }, "typing-extensions": { "hashes": [ - "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", - "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0", + "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a" ], "markers": "python_version >= '3.8'", - "version": "==4.9.0" + "version": "==4.11.0" }, "wrapt": { "hashes": [ @@ -413,6 +414,14 @@ "markers": "python_version >= '3.7'", "version": "==2.14.0" }, + "backports.tarfile": { + "hashes": [ + "sha256:2688f159c21afd56a07b75f01306f9f52c79aebcc5f4a117fb8fbb4445352c75", + "sha256:bcd36290d9684beb524d3fe74f4a2db056824c47746583f090b8e55daf0776e4" + ], + "markers": "python_version < '3.12'", + "version": "==1.0.0" + }, "black": { "hashes": [ "sha256:06f9d8846f2340dfac80ceb20200ea5d1b3f181dd0556b47af4e8e0b24fa0a6b", @@ -445,11 +454,69 @@ }, "certifi": { "hashes": [ - "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1", - "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474" + "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", + "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" ], "markers": "python_version >= '3.6'", - "version": "==2023.11.17" + "version": "==2024.2.2" + }, + "cffi": { + "hashes": [ + "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc", + "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a", + "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417", + "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab", + "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520", + "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36", + "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743", + "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8", + "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed", + "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684", + "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56", + "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324", + "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d", + "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235", + "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e", + "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088", + "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000", + "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7", + "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e", + "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673", + "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c", + "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe", + "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2", + "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098", + "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8", + "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a", + "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0", + "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b", + "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896", + "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e", + "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9", + "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2", + "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b", + "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6", + "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404", + "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f", + "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0", + "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4", + "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc", + "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936", + "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba", + "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872", + "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb", + "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614", + "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1", + "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d", + "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969", + "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b", + "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4", + "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627", + "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956", + "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357" + ], + "markers": "platform_python_implementation != 'PyPy'", + "version": "==1.16.0" }, "charset-normalizer": { "hashes": [ @@ -565,53 +632,53 @@ }, "contourpy": { "hashes": [ - "sha256:0274c1cb63625972c0c007ab14dd9ba9e199c36ae1a231ce45d725cbcbfd10a8", - "sha256:0d7e03c0f9a4f90dc18d4e77e9ef4ec7b7bbb437f7f675be8e530d65ae6ef956", - "sha256:11f8d2554e52f459918f7b8e6aa20ec2a3bce35ce95c1f0ef4ba36fbda306df5", - "sha256:139d8d2e1c1dd52d78682f505e980f592ba53c9f73bd6be102233e358b401063", - "sha256:16a7380e943a6d52472096cb7ad5264ecee36ed60888e2a3d3814991a0107286", - "sha256:171f311cb758de7da13fc53af221ae47a5877be5a0843a9fe150818c51ed276a", - "sha256:18fc2b4ed8e4a8fe849d18dce4bd3c7ea637758c6343a1f2bae1e9bd4c9f4686", - "sha256:1c203f617abc0dde5792beb586f827021069fb6d403d7f4d5c2b543d87edceb9", - "sha256:1c2559d6cffc94890b0529ea7eeecc20d6fadc1539273aa27faf503eb4656d8f", - "sha256:1c88dfb9e0c77612febebb6ac69d44a8d81e3dc60f993215425b62c1161353f4", - "sha256:1e9dc350fb4c58adc64df3e0703ab076f60aac06e67d48b3848c23647ae4310e", - "sha256:247b9d16535acaa766d03037d8e8fb20866d054d3c7fbf6fd1f993f11fc60ca0", - "sha256:266270c6f6608340f6c9836a0fb9b367be61dde0c9a9a18d5ece97774105ff3e", - "sha256:34b9071c040d6fe45d9826cbbe3727d20d83f1b6110d219b83eb0e2a01d79488", - "sha256:3d7d1f8871998cdff5d2ff6a087e5e1780139abe2838e85b0b46b7ae6cc25399", - "sha256:461e3ae84cd90b30f8d533f07d87c00379644205b1d33a5ea03381edc4b69431", - "sha256:464b423bc2a009088f19bdf1f232299e8b6917963e2b7e1d277da5041f33a779", - "sha256:491b1917afdd8638a05b611a56d46587d5a632cabead889a5440f7c638bc6ed9", - "sha256:4a1b1208102be6e851f20066bf0e7a96b7d48a07c9b0cfe6d0d4545c2f6cadab", - "sha256:575bcaf957a25d1194903a10bc9f316c136c19f24e0985a2b9b5608bdf5dbfe0", - "sha256:5c6b28956b7b232ae801406e529ad7b350d3f09a4fde958dfdf3c0520cdde0dd", - "sha256:5d16edfc3fc09968e09ddffada434b3bf989bf4911535e04eada58469873e28e", - "sha256:5fd1810973a375ca0e097dee059c407913ba35723b111df75671a1976efa04bc", - "sha256:67b7f17679fa62ec82b7e3e611c43a016b887bd64fb933b3ae8638583006c6d6", - "sha256:68ce4788b7d93e47f84edd3f1f95acdcd142ae60bc0e5493bfd120683d2d4316", - "sha256:6d3364b999c62f539cd403f8123ae426da946e142312a514162adb2addd8d808", - "sha256:6e739530c662a8d6d42c37c2ed52a6f0932c2d4a3e8c1f90692ad0ce1274abe0", - "sha256:6fdd887f17c2f4572ce548461e4f96396681212d858cae7bd52ba3310bc6f00f", - "sha256:78e6ad33cf2e2e80c5dfaaa0beec3d61face0fb650557100ee36db808bfa6843", - "sha256:884c3f9d42d7218304bc74a8a7693d172685c84bd7ab2bab1ee567b769696df9", - "sha256:8d8faf05be5ec8e02a4d86f616fc2a0322ff4a4ce26c0f09d9f7fb5330a35c95", - "sha256:999c71939aad2780f003979b25ac5b8f2df651dac7b38fb8ce6c46ba5abe6ae9", - "sha256:99ad97258985328b4f207a5e777c1b44a83bfe7cf1f87b99f9c11d4ee477c4de", - "sha256:9e6c93b5b2dbcedad20a2f18ec22cae47da0d705d454308063421a3b290d9ea4", - "sha256:ab459a1cbbf18e8698399c595a01f6dcc5c138220ca3ea9e7e6126232d102bb4", - "sha256:b69303ceb2e4d4f146bf82fda78891ef7bcd80c41bf16bfca3d0d7eb545448aa", - "sha256:b7caf9b241464c404613512d5594a6e2ff0cc9cb5615c9475cc1d9b514218ae8", - "sha256:b95a225d4948b26a28c08307a60ac00fb8671b14f2047fc5476613252a129776", - "sha256:bd2f1ae63998da104f16a8b788f685e55d65760cd1929518fd94cd682bf03e41", - "sha256:be16975d94c320432657ad2402f6760990cb640c161ae6da1363051805fa8108", - "sha256:ce96dd400486e80ac7d195b2d800b03e3e6a787e2a522bfb83755938465a819e", - "sha256:dbd50d0a0539ae2e96e537553aff6d02c10ed165ef40c65b0e27e744a0f10af8", - "sha256:dd10c26b4eadae44783c45ad6655220426f971c61d9b239e6f7b16d5cdaaa727", - "sha256:ebeac59e9e1eb4b84940d076d9f9a6cec0064e241818bcb6e32124cc5c3e377a" + "sha256:00e5388f71c1a0610e6fe56b5c44ab7ba14165cdd6d695429c5cd94021e390b2", + "sha256:10a37ae557aabf2509c79715cd20b62e4c7c28b8cd62dd7d99e5ed3ce28c3fd9", + "sha256:11959f0ce4a6f7b76ec578576a0b61a28bdc0696194b6347ba3f1c53827178b9", + "sha256:187fa1d4c6acc06adb0fae5544c59898ad781409e61a926ac7e84b8f276dcef4", + "sha256:1a07fc092a4088ee952ddae19a2b2a85757b923217b7eed584fdf25f53a6e7ce", + "sha256:1cac0a8f71a041aa587410424ad46dfa6a11f6149ceb219ce7dd48f6b02b87a7", + "sha256:1d59e739ab0e3520e62a26c60707cc3ab0365d2f8fecea74bfe4de72dc56388f", + "sha256:2855c8b0b55958265e8b5888d6a615ba02883b225f2227461aa9127c578a4922", + "sha256:2e785e0f2ef0d567099b9ff92cbfb958d71c2d5b9259981cd9bee81bd194c9a4", + "sha256:309be79c0a354afff9ff7da4aaed7c3257e77edf6c1b448a779329431ee79d7e", + "sha256:39f3ecaf76cd98e802f094e0d4fbc6dc9c45a8d0c4d185f0f6c2234e14e5f75b", + "sha256:457499c79fa84593f22454bbd27670227874cd2ff5d6c84e60575c8b50a69619", + "sha256:49e70d111fee47284d9dd867c9bb9a7058a3c617274900780c43e38d90fe1205", + "sha256:4c75507d0a55378240f781599c30e7776674dbaf883a46d1c90f37e563453480", + "sha256:4c863140fafc615c14a4bf4efd0f4425c02230eb8ef02784c9a156461e62c965", + "sha256:4d8908b3bee1c889e547867ca4cdc54e5ab6be6d3e078556814a22457f49423c", + "sha256:5b9eb0ca724a241683c9685a484da9d35c872fd42756574a7cfbf58af26677fd", + "sha256:6022cecf8f44e36af10bd9118ca71f371078b4c168b6e0fab43d4a889985dbb5", + "sha256:6150ffa5c767bc6332df27157d95442c379b7dce3a38dff89c0f39b63275696f", + "sha256:62828cada4a2b850dbef89c81f5a33741898b305db244904de418cc957ff05dc", + "sha256:7b4182299f251060996af5249c286bae9361fa8c6a9cda5efc29fe8bfd6062ec", + "sha256:94b34f32646ca0414237168d68a9157cb3889f06b096612afdd296003fdd32fd", + "sha256:9ce6889abac9a42afd07a562c2d6d4b2b7134f83f18571d859b25624a331c90b", + "sha256:9cffe0f850e89d7c0012a1fb8730f75edd4320a0a731ed0c183904fe6ecfc3a9", + "sha256:a12a813949e5066148712a0626895c26b2578874e4cc63160bb007e6df3436fe", + "sha256:a1eea9aecf761c661d096d39ed9026574de8adb2ae1c5bd7b33558af884fb2ce", + "sha256:a31f94983fecbac95e58388210427d68cd30fe8a36927980fab9c20062645609", + "sha256:ac58bdee53cbeba2ecad824fa8159493f0bf3b8ea4e93feb06c9a465d6c87da8", + "sha256:af3f4485884750dddd9c25cb7e3915d83c2db92488b38ccb77dd594eac84c4a0", + "sha256:b33d2bc4f69caedcd0a275329eb2198f560b325605810895627be5d4b876bf7f", + "sha256:b59c0ffceff8d4d3996a45f2bb6f4c207f94684a96bf3d9728dbb77428dd8cb8", + "sha256:bb6834cbd983b19f06908b45bfc2dad6ac9479ae04abe923a275b5f48f1a186b", + "sha256:bd3db01f59fdcbce5b22afad19e390260d6d0222f35a1023d9adc5690a889364", + "sha256:bd7c23df857d488f418439686d3b10ae2fbf9bc256cd045b37a8c16575ea1040", + "sha256:c2528d60e398c7c4c799d56f907664673a807635b857df18f7ae64d3e6ce2d9f", + "sha256:d31a63bc6e6d87f77d71e1abbd7387ab817a66733734883d1fc0021ed9bfa083", + "sha256:d4492d82b3bc7fbb7e3610747b159869468079fe149ec5c4d771fa1f614a14df", + "sha256:ddcb8581510311e13421b1f544403c16e901c4e8f09083c881fab2be80ee31ba", + "sha256:e1d59258c3c67c865435d8fbeb35f8c59b8bef3d6f46c1f29f6123556af28445", + "sha256:eb3315a8a236ee19b6df481fc5f997436e8ade24a9f03dfdc6bd490fea20c6da", + "sha256:ef2b055471c0eb466033760a521efb9d8a32b99ab907fc8358481a1dd29e3bd3", + "sha256:ef5adb9a3b1d0c645ff694f9bca7702ec2c70f4d734f9922ea34de02294fdf72", + "sha256:f32c38afb74bd98ce26de7cc74a67b40afb7b05aae7b42924ea990d51e4dac02", + "sha256:fe0ccca550bb8e5abc22f530ec0466136379c01321fd94f30a22231e8a48d985" ], "markers": "python_version >= '3.9'", - "version": "==1.2.0" + "version": "==1.2.1" }, "coverage": { "extras": [ @@ -675,6 +742,44 @@ "markers": "python_version >= '3.8'", "version": "==7.4.1" }, + "cryptography": { + "hashes": [ + "sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee", + "sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576", + "sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d", + "sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30", + "sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413", + "sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb", + "sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da", + "sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4", + "sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd", + "sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc", + "sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8", + "sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1", + "sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc", + "sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e", + "sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8", + "sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940", + "sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400", + "sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7", + "sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16", + "sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278", + "sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74", + "sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec", + "sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1", + "sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2", + "sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c", + "sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922", + "sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a", + "sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6", + "sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1", + "sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e", + "sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac", + "sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7" + ], + "markers": "python_version >= '3.7'", + "version": "==42.0.5" + }, "cycler": { "hashes": [ "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", @@ -710,11 +815,11 @@ }, "execnet": { "hashes": [ - "sha256:88256416ae766bc9e8895c76a87928c0012183da3cc4fc18016e6f050e025f41", - "sha256:cc59bc4423742fd71ad227122eb0dd44db51efb3dc4095b45ac9a08c770096af" + "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", + "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3" ], - "markers": "python_version >= '3.7'", - "version": "==2.0.2" + "markers": "python_version >= '3.8'", + "version": "==2.1.1" }, "flake8": { "hashes": [ @@ -754,51 +859,51 @@ }, "fonttools": { "hashes": [ - "sha256:0255dbc128fee75fb9be364806b940ed450dd6838672a150d501ee86523ac61e", - "sha256:0a00bd0e68e88987dcc047ea31c26d40a3c61185153b03457956a87e39d43c37", - "sha256:0a1d313a415eaaba2b35d6cd33536560deeebd2ed758b9bfb89ab5d97dc5deac", - "sha256:0f750037e02beb8b3569fbff701a572e62a685d2a0e840d75816592280e5feae", - "sha256:13819db8445a0cec8c3ff5f243af6418ab19175072a9a92f6cc8ca7d1452754b", - "sha256:254d9a6f7be00212bf0c3159e0a420eb19c63793b2c05e049eb337f3023c5ecc", - "sha256:29495d6d109cdbabe73cfb6f419ce67080c3ef9ea1e08d5750240fd4b0c4763b", - "sha256:32ab2e9702dff0dd4510c7bb958f265a8d3dd5c0e2547e7b5f7a3df4979abb07", - "sha256:3480eeb52770ff75140fe7d9a2ec33fb67b07efea0ab5129c7e0c6a639c40c70", - "sha256:3a808f3c1d1df1f5bf39be869b6e0c263570cdafb5bdb2df66087733f566ea71", - "sha256:3b629108351d25512d4ea1a8393a2dba325b7b7d7308116b605ea3f8e1be88df", - "sha256:3d71606c9321f6701642bd4746f99b6089e53d7e9817fc6b964e90d9c5f0ecc6", - "sha256:3e2b95dce2ead58fb12524d0ca7d63a63459dd489e7e5838c3cd53557f8933e1", - "sha256:4a5a5318ba5365d992666ac4fe35365f93004109d18858a3e18ae46f67907670", - "sha256:4c811d3c73b6abac275babb8aa439206288f56fdb2c6f8835e3d7b70de8937a7", - "sha256:4e743935139aa485fe3253fc33fe467eab6ea42583fa681223ea3f1a93dd01e6", - "sha256:4ec558c543609e71b2275c4894e93493f65d2f41c15fe1d089080c1d0bb4d635", - "sha256:5465df494f20a7d01712b072ae3ee9ad2887004701b95cb2cc6dcb9c2c97a899", - "sha256:5b60e3afa9635e3dfd3ace2757039593e3bd3cf128be0ddb7a1ff4ac45fa5a50", - "sha256:63fbed184979f09a65aa9c88b395ca539c94287ba3a364517698462e13e457c9", - "sha256:69731e8bea0578b3c28fdb43dbf95b9386e2d49a399e9a4ad736b8e479b08085", - "sha256:6dd58cc03016b281bd2c74c84cdaa6bd3ce54c5a7f47478b7657b930ac3ed8eb", - "sha256:740947906590a878a4bde7dd748e85fefa4d470a268b964748403b3ab2aeed6c", - "sha256:7df26dd3650e98ca45f1e29883c96a0b9f5bb6af8d632a6a108bc744fa0bd9b3", - "sha256:7eb7ad665258fba68fd22228a09f347469d95a97fb88198e133595947a20a184", - "sha256:7ee48bd9d6b7e8f66866c9090807e3a4a56cf43ffad48962725a190e0dd774c8", - "sha256:86e0427864c6c91cf77f16d1fb9bf1bbf7453e824589e8fb8461b6ee1144f506", - "sha256:8f57ecd742545362a0f7186774b2d1c53423ed9ece67689c93a1055b236f638c", - "sha256:90f898cdd67f52f18049250a6474185ef6544c91f27a7bee70d87d77a8daf89c", - "sha256:94208ea750e3f96e267f394d5588579bb64cc628e321dbb1d4243ffbc291b18b", - "sha256:a1c154bb85dc9a4cf145250c88d112d88eb414bad81d4cb524d06258dea1bdc0", - "sha256:a5d77479fb885ef38a16a253a2f4096bc3d14e63a56d6246bfdb56365a12b20c", - "sha256:a86a5ab2873ed2575d0fcdf1828143cfc6b977ac448e3dc616bb1e3d20efbafa", - "sha256:ac71e2e201df041a2891067dc36256755b1229ae167edbdc419b16da78732c2f", - "sha256:b3e1304e5f19ca861d86a72218ecce68f391646d85c851742d265787f55457a4", - "sha256:b8be28c036b9f186e8c7eaf8a11b42373e7e4949f9e9f370202b9da4c4c3f56c", - "sha256:c19044256c44fe299d9a73456aabee4b4d06c6b930287be93b533b4737d70aa1", - "sha256:d49ce3ea7b7173faebc5664872243b40cf88814ca3eb135c4a3cdff66af71946", - "sha256:e040f905d542362e07e72e03612a6270c33d38281fd573160e1003e43718d68d", - "sha256:eabae77a07c41ae0b35184894202305c3ad211a93b2eb53837c2a1143c8bc952", - "sha256:f791446ff297fd5f1e2247c188de53c1bfb9dd7f0549eba55b73a3c2087a2703", - "sha256:f83a4daef6d2a202acb9bf572958f91cfde5b10c8ee7fb1d09a4c81e5d851fd8" + "sha256:0118ef998a0699a96c7b28457f15546815015a2710a1b23a7bf6c1be60c01636", + "sha256:0d145976194a5242fdd22df18a1b451481a88071feadf251221af110ca8f00ce", + "sha256:0e19bd9e9964a09cd2433a4b100ca7f34e34731e0758e13ba9a1ed6e5468cc0f", + "sha256:0f08c901d3866a8905363619e3741c33f0a83a680d92a9f0e575985c2634fcc1", + "sha256:1250e818b5f8a679ad79660855528120a8f0288f8f30ec88b83db51515411fcc", + "sha256:15c94eeef6b095831067f72c825eb0e2d48bb4cea0647c1b05c981ecba2bf39f", + "sha256:1621ee57da887c17312acc4b0e7ac30d3a4fb0fec6174b2e3754a74c26bbed1e", + "sha256:180194c7fe60c989bb627d7ed5011f2bef1c4d36ecf3ec64daec8302f1ae0716", + "sha256:278e50f6b003c6aed19bae2242b364e575bcb16304b53f2b64f6551b9c000e15", + "sha256:32b17504696f605e9e960647c5f64b35704782a502cc26a37b800b4d69ff3c77", + "sha256:3bee3f3bd9fa1d5ee616ccfd13b27ca605c2b4270e45715bd2883e9504735034", + "sha256:4060acc2bfa2d8e98117828a238889f13b6f69d59f4f2d5857eece5277b829ba", + "sha256:54dcf21a2f2d06ded676e3c3f9f74b2bafded3a8ff12f0983160b13e9f2fb4a7", + "sha256:56fc244f2585d6c00b9bcc59e6593e646cf095a96fe68d62cd4da53dd1287b55", + "sha256:599bdb75e220241cedc6faebfafedd7670335d2e29620d207dd0378a4e9ccc5a", + "sha256:5f6bc991d1610f5c3bbe997b0233cbc234b8e82fa99fc0b2932dc1ca5e5afec0", + "sha256:60a3409c9112aec02d5fb546f557bca6efa773dcb32ac147c6baf5f742e6258b", + "sha256:68b3fb7775a923be73e739f92f7e8a72725fd333eab24834041365d2278c3671", + "sha256:76f1777d8b3386479ffb4a282e74318e730014d86ce60f016908d9801af9ca2a", + "sha256:806e7912c32a657fa39d2d6eb1d3012d35f841387c8fc6cf349ed70b7c340039", + "sha256:84d7751f4468dd8cdd03ddada18b8b0857a5beec80bce9f435742abc9a851a74", + "sha256:865a58b6e60b0938874af0968cd0553bcd88e0b2cb6e588727117bd099eef836", + "sha256:8ac27f436e8af7779f0bb4d5425aa3535270494d3bc5459ed27de3f03151e4c2", + "sha256:8b4850fa2ef2cfbc1d1f689bc159ef0f45d8d83298c1425838095bf53ef46308", + "sha256:8b5ad456813d93b9c4b7ee55302208db2b45324315129d85275c01f5cb7e61a2", + "sha256:8e2f1a4499e3b5ee82c19b5ee57f0294673125c65b0a1ff3764ea1f9db2f9ef5", + "sha256:9696fe9f3f0c32e9a321d5268208a7cc9205a52f99b89479d1b035ed54c923f1", + "sha256:96a48e137c36be55e68845fc4284533bda2980f8d6f835e26bca79d7e2006438", + "sha256:a8feca65bab31479d795b0d16c9a9852902e3a3c0630678efb0b2b7941ea9c74", + "sha256:aefa011207ed36cd280babfaa8510b8176f1a77261833e895a9d96e57e44802f", + "sha256:b2b92381f37b39ba2fc98c3a45a9d6383bfc9916a87d66ccb6553f7bdd129097", + "sha256:b3c61423f22165541b9403ee39874dcae84cd57a9078b82e1dce8cb06b07fa2e", + "sha256:b5b48a1121117047d82695d276c2af2ee3a24ffe0f502ed581acc2673ecf1037", + "sha256:c18b49adc721a7d0b8dfe7c3130c89b8704baf599fb396396d07d4aa69b824a1", + "sha256:c5b8cab0c137ca229433570151b5c1fc6af212680b58b15abd797dcdd9dd5051", + "sha256:c7e91abdfae1b5c9e3a543f48ce96013f9a08c6c9668f1e6be0beabf0a569c1b", + "sha256:cadf4e12a608ef1d13e039864f484c8a968840afa0258b0b843a0556497ea9ed", + "sha256:dc0673361331566d7a663d7ce0f6fdcbfbdc1f59c6e3ed1165ad7202ca183c68", + "sha256:de7c29bdbdd35811f14493ffd2534b88f0ce1b9065316433b22d63ca1cd21f14", + "sha256:e9d9298be7a05bb4801f558522adbe2feea1b0b103d5294ebf24a92dd49b78e5", + "sha256:ee1af4be1c5afe4c96ca23badd368d8dc75f611887fb0c0dac9f71ee5d6f110e", + "sha256:f7e89853d8bea103c8e3514b9f9dc86b5b4120afb4583b57eb10dfa5afbe0936" ], "markers": "python_version >= '3.8'", - "version": "==4.47.2" + "version": "==4.51.0" }, "gprof2dot": { "hashes": [ @@ -819,11 +924,11 @@ }, "idna": { "hashes": [ - "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", - "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" + "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", + "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" ], "markers": "python_version >= '3.5'", - "version": "==3.6" + "version": "==3.7" }, "imagesize": { "hashes": [ @@ -835,11 +940,11 @@ }, "importlib-metadata": { "hashes": [ - "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e", - "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc" + "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570", + "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2" ], "markers": "python_version >= '3.8'", - "version": "==7.0.1" + "version": "==7.1.0" }, "iniconfig": { "hashes": [ @@ -851,11 +956,35 @@ }, "jaraco.classes": { "hashes": [ - "sha256:10afa92b6743f25c0cf5f37c6bb6e18e2c5bb84a16527ccfc0040ea377e7aaeb", - "sha256:c063dd08e89217cee02c8d5e5ec560f2c8ce6cdc2fcdc2e68f7b2e5547ed3621" + "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", + "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790" ], "markers": "python_version >= '3.8'", - "version": "==3.3.0" + "version": "==3.4.0" + }, + "jaraco.context": { + "hashes": [ + "sha256:3e16388f7da43d384a1a7cd3452e72e14732ac9fe459678773a3608a812bf266", + "sha256:c2f67165ce1f9be20f32f650f25d8edfc1646a8aeee48ae06fb35f90763576d2" + ], + "markers": "python_version >= '3.8'", + "version": "==5.3.0" + }, + "jaraco.functools": { + "hashes": [ + "sha256:c279cb24c93d694ef7270f970d499cab4d3813f4e08273f95398651a634f0925", + "sha256:daf276ddf234bea897ef14f43c4e1bf9eefeac7b7a82a4dd69228ac20acff68d" + ], + "markers": "python_version >= '3.8'", + "version": "==4.0.0" + }, + "jeepney": { + "hashes": [ + "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806", + "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755" + ], + "markers": "sys_platform == 'linux'", + "version": "==0.8.0" }, "jinja2": { "hashes": [ @@ -866,13 +995,22 @@ "markers": "python_version >= '3.6'", "version": "==3.0.3" }, + "jsonschema": { + "hashes": [ + "sha256:0f864437ab8b6076ba6707453ef8f98a6a0d512a80e93f8abdb676f737ecb60d", + "sha256:a870ad254da1a8ca84b6a2905cac29d265f805acc57af304784962a2aa6508f6" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==4.17.3" + }, "keyring": { "hashes": [ - "sha256:4446d35d636e6a10b8bce7caa66913dd9eca5fd222ca03a3d42c38608ac30836", - "sha256:e730ecffd309658a08ee82535a3b5ec4b4c8669a9be11efb66249d8e0aeb9a25" + "sha256:26fc12e6a329d61d24aa47b22a7c5c3f35753df7d8f2860973cf94f4e1fb3427", + "sha256:7230ea690525133f6ad536a9b5def74a4bd52642abe594761028fc044d7c7893" ], "markers": "python_version >= '3.8'", - "version": "==24.3.0" + "version": "==25.1.0" }, "kiwisolver": { "hashes": [ @@ -994,103 +1132,103 @@ }, "markupsafe": { "hashes": [ - "sha256:0042d6a9880b38e1dd9ff83146cc3c9c18a059b9360ceae207805567aacccc69", - "sha256:0c26f67b3fe27302d3a412b85ef696792c4a2386293c53ba683a89562f9399b0", - "sha256:0fbad3d346df8f9d72622ac71b69565e621ada2ce6572f37c2eae8dacd60385d", - "sha256:15866d7f2dc60cfdde12ebb4e75e41be862348b4728300c36cdf405e258415ec", - "sha256:1c98c33ffe20e9a489145d97070a435ea0679fddaabcafe19982fe9c971987d5", - "sha256:21e7af8091007bf4bebf4521184f4880a6acab8df0df52ef9e513d8e5db23411", - "sha256:23984d1bdae01bee794267424af55eef4dfc038dc5d1272860669b2aa025c9e3", - "sha256:31f57d64c336b8ccb1966d156932f3daa4fee74176b0fdc48ef580be774aae74", - "sha256:3583a3a3ab7958e354dc1d25be74aee6228938312ee875a22330c4dc2e41beb0", - "sha256:36d7626a8cca4d34216875aee5a1d3d654bb3dac201c1c003d182283e3205949", - "sha256:396549cea79e8ca4ba65525470d534e8a41070e6b3500ce2414921099cb73e8d", - "sha256:3a66c36a3864df95e4f62f9167c734b3b1192cb0851b43d7cc08040c074c6279", - "sha256:3aae9af4cac263007fd6309c64c6ab4506dd2b79382d9d19a1994f9240b8db4f", - "sha256:3ab3a886a237f6e9c9f4f7d272067e712cdb4efa774bef494dccad08f39d8ae6", - "sha256:47bb5f0142b8b64ed1399b6b60f700a580335c8e1c57f2f15587bd072012decc", - "sha256:49a3b78a5af63ec10d8604180380c13dcd870aba7928c1fe04e881d5c792dc4e", - "sha256:4df98d4a9cd6a88d6a585852f56f2155c9cdb6aec78361a19f938810aa020954", - "sha256:5045e892cfdaecc5b4c01822f353cf2c8feb88a6ec1c0adef2a2e705eef0f656", - "sha256:5244324676254697fe5c181fc762284e2c5fceeb1c4e3e7f6aca2b6f107e60dc", - "sha256:54635102ba3cf5da26eb6f96c4b8c53af8a9c0d97b64bdcb592596a6255d8518", - "sha256:54a7e1380dfece8847c71bf7e33da5d084e9b889c75eca19100ef98027bd9f56", - "sha256:55d03fea4c4e9fd0ad75dc2e7e2b6757b80c152c032ea1d1de487461d8140efc", - "sha256:698e84142f3f884114ea8cf83e7a67ca8f4ace8454e78fe960646c6c91c63bfa", - "sha256:6aa5e2e7fc9bc042ae82d8b79d795b9a62bd8f15ba1e7594e3db243f158b5565", - "sha256:7653fa39578957bc42e5ebc15cf4361d9e0ee4b702d7d5ec96cdac860953c5b4", - "sha256:765f036a3d00395a326df2835d8f86b637dbaf9832f90f5d196c3b8a7a5080cb", - "sha256:78bc995e004681246e85e28e068111a4c3f35f34e6c62da1471e844ee1446250", - "sha256:7a07f40ef8f0fbc5ef1000d0c78771f4d5ca03b4953fc162749772916b298fc4", - "sha256:8b570a1537367b52396e53325769608f2a687ec9a4363647af1cded8928af959", - "sha256:987d13fe1d23e12a66ca2073b8d2e2a75cec2ecb8eab43ff5624ba0ad42764bc", - "sha256:9896fca4a8eb246defc8b2a7ac77ef7553b638e04fbf170bff78a40fa8a91474", - "sha256:9e9e3c4020aa2dc62d5dd6743a69e399ce3de58320522948af6140ac959ab863", - "sha256:a0b838c37ba596fcbfca71651a104a611543077156cb0a26fe0c475e1f152ee8", - "sha256:a4d176cfdfde84f732c4a53109b293d05883e952bbba68b857ae446fa3119b4f", - "sha256:a76055d5cb1c23485d7ddae533229039b850db711c554a12ea64a0fd8a0129e2", - "sha256:a76cd37d229fc385738bd1ce4cba2a121cf26b53864c1772694ad0ad348e509e", - "sha256:a7cc49ef48a3c7a0005a949f3c04f8baa5409d3f663a1b36f0eba9bfe2a0396e", - "sha256:abf5ebbec056817057bfafc0445916bb688a255a5146f900445d081db08cbabb", - "sha256:b0fe73bac2fed83839dbdbe6da84ae2a31c11cfc1c777a40dbd8ac8a6ed1560f", - "sha256:b6f14a9cd50c3cb100eb94b3273131c80d102e19bb20253ac7bd7336118a673a", - "sha256:b83041cda633871572f0d3c41dddd5582ad7d22f65a72eacd8d3d6d00291df26", - "sha256:b835aba863195269ea358cecc21b400276747cc977492319fd7682b8cd2c253d", - "sha256:bf1196dcc239e608605b716e7b166eb5faf4bc192f8a44b81e85251e62584bd2", - "sha256:c669391319973e49a7c6230c218a1e3044710bc1ce4c8e6eb71f7e6d43a2c131", - "sha256:c7556bafeaa0a50e2fe7dc86e0382dea349ebcad8f010d5a7dc6ba568eaaa789", - "sha256:c8f253a84dbd2c63c19590fa86a032ef3d8cc18923b8049d91bcdeeb2581fbf6", - "sha256:d18b66fe626ac412d96c2ab536306c736c66cf2a31c243a45025156cc190dc8a", - "sha256:d5291d98cd3ad9a562883468c690a2a238c4a6388ab3bd155b0c75dd55ece858", - "sha256:d5c31fe855c77cad679b302aabc42d724ed87c043b1432d457f4976add1c2c3e", - "sha256:d6e427c7378c7f1b2bef6a344c925b8b63623d3321c09a237b7cc0e77dd98ceb", - "sha256:dac1ebf6983148b45b5fa48593950f90ed6d1d26300604f321c74a9ca1609f8e", - "sha256:de8153a7aae3835484ac168a9a9bdaa0c5eee4e0bc595503c95d53b942879c84", - "sha256:e1a0d1924a5013d4f294087e00024ad25668234569289650929ab871231668e7", - "sha256:e7902211afd0af05fbadcc9a312e4cf10f27b779cf1323e78d52377ae4b72bea", - "sha256:e888ff76ceb39601c59e219f281466c6d7e66bd375b4ec1ce83bcdc68306796b", - "sha256:f06e5a9e99b7df44640767842f414ed5d7bedaaa78cd817ce04bbd6fd86e2dd6", - "sha256:f6be2d708a9d0e9b0054856f07ac7070fbe1754be40ca8525d5adccdbda8f475", - "sha256:f9917691f410a2e0897d1ef99619fd3f7dd503647c8ff2475bf90c3cf222ad74", - "sha256:fc1a75aa8f11b87910ffd98de62b29d6520b6d6e8a3de69a70ca34dea85d2a8a", - "sha256:fe8512ed897d5daf089e5bd010c3dc03bb1bdae00b35588c49b98268d4a01e00" + "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf", + "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff", + "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f", + "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3", + "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532", + "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f", + "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617", + "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df", + "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4", + "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906", + "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f", + "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", + "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8", + "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371", + "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2", + "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465", + "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52", + "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6", + "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", + "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad", + "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", + "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0", + "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029", + "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", + "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a", + "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", + "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5", + "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c", + "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf", + "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9", + "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", + "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", + "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3", + "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", + "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46", + "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc", + "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a", + "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", + "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900", + "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5", + "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea", + "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", + "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5", + "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e", + "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a", + "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f", + "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50", + "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", + "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", + "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4", + "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff", + "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2", + "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46", + "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", + "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf", + "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", + "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5", + "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab", + "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd", + "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68" ], "markers": "python_version >= '3.7'", - "version": "==2.1.4" + "version": "==2.1.5" }, "matplotlib": { "hashes": [ - "sha256:01a978b871b881ee76017152f1f1a0cbf6bd5f7b8ff8c96df0df1bd57d8755a1", - "sha256:03f9d160a29e0b65c0790bb07f4f45d6a181b1ac33eb1bb0dd225986450148f0", - "sha256:091275d18d942cf1ee9609c830a1bc36610607d8223b1b981c37d5c9fc3e46a4", - "sha256:09796f89fb71a0c0e1e2f4bdaf63fb2cefc84446bb963ecdeb40dfee7dfa98c7", - "sha256:0f4fc5d72b75e2c18e55eb32292659cf731d9d5b312a6eb036506304f4675630", - "sha256:172f4d0fbac3383d39164c6caafd3255ce6fa58f08fc392513a0b1d3b89c4f89", - "sha256:1b0f3b8ea0e99e233a4bcc44590f01604840d833c280ebb8fe5554fd3e6cfe8d", - "sha256:3773002da767f0a9323ba1a9b9b5d00d6257dbd2a93107233167cfb581f64717", - "sha256:46a569130ff53798ea5f50afce7406e91fdc471ca1e0e26ba976a8c734c9427a", - "sha256:4c318c1e95e2f5926fba326f68177dee364aa791d6df022ceb91b8221bd0a627", - "sha256:4e208f46cf6576a7624195aa047cb344a7f802e113bb1a06cfd4bee431de5e31", - "sha256:533b0e3b0c6768eef8cbe4b583731ce25a91ab54a22f830db2b031e83cca9213", - "sha256:5864bdd7da445e4e5e011b199bb67168cdad10b501750367c496420f2ad00843", - "sha256:5ba9cbd8ac6cf422f3102622b20f8552d601bf8837e49a3afed188d560152788", - "sha256:6f9c6976748a25e8b9be51ea028df49b8e561eed7809146da7a47dbecebab367", - "sha256:7c48d9e221b637c017232e3760ed30b4e8d5dfd081daf327e829bf2a72c731b4", - "sha256:830f00640c965c5b7f6bc32f0d4ce0c36dfe0379f7dd65b07a00c801713ec40a", - "sha256:9a5430836811b7652991939012f43d2808a2db9b64ee240387e8c43e2e5578c8", - "sha256:aa11b3c6928a1e496c1a79917d51d4cd5d04f8a2e75f21df4949eeefdf697f4b", - "sha256:b78e4f2cedf303869b782071b55fdde5987fda3038e9d09e58c91cc261b5ad18", - "sha256:b9576723858a78751d5aacd2497b8aef29ffea6d1c95981505877f7ac28215c6", - "sha256:bddfb1db89bfaa855912261c805bd0e10218923cc262b9159a49c29a7a1c1afa", - "sha256:c7d36c2209d9136cd8e02fab1c0ddc185ce79bc914c45054a9f514e44c787917", - "sha256:d1095fecf99eeb7384dabad4bf44b965f929a5f6079654b681193edf7169ec20", - "sha256:d7b1704a530395aaf73912be741c04d181f82ca78084fbd80bc737be04848331", - "sha256:d86593ccf546223eb75a39b44c32788e6f6440d13cfc4750c1c15d0fcb850b63", - "sha256:deaed9ad4da0b1aea77fe0aa0cebb9ef611c70b3177be936a95e5d01fa05094f", - "sha256:ef8345b48e95cee45ff25192ed1f4857273117917a4dcd48e3905619bcd9c9b8" + "sha256:1c13f041a7178f9780fb61cc3a2b10423d5e125480e4be51beaf62b172413b67", + "sha256:232ce322bfd020a434caaffbd9a95333f7c2491e59cfc014041d95e38ab90d1c", + "sha256:493e9f6aa5819156b58fce42b296ea31969f2aab71c5b680b4ea7a3cb5c07d94", + "sha256:50bac6e4d77e4262c4340d7a985c30912054745ec99756ce213bfbc3cb3808eb", + "sha256:606e3b90897554c989b1e38a258c626d46c873523de432b1462f295db13de6f9", + "sha256:6209e5c9aaccc056e63b547a8152661324404dd92340a6e479b3a7f24b42a5d0", + "sha256:6485ac1f2e84676cff22e693eaa4fbed50ef5dc37173ce1f023daef4687df616", + "sha256:6addbd5b488aedb7f9bc19f91cd87ea476206f45d7116fcfe3d31416702a82fa", + "sha256:72f9322712e4562e792b2961971891b9fbbb0e525011e09ea0d1f416c4645661", + "sha256:7a6769f58ce51791b4cb8b4d7642489df347697cd3e23d88266aaaee93b41d9a", + "sha256:8080d5081a86e690d7688ffa542532e87f224c38a6ed71f8fbed34dd1d9fedae", + "sha256:843cbde2f0946dadd8c5c11c6d91847abd18ec76859dc319362a0964493f0ba6", + "sha256:8aac397d5e9ec158960e31c381c5ffc52ddd52bd9a47717e2a694038167dffea", + "sha256:8f65c9f002d281a6e904976007b2d46a1ee2bcea3a68a8c12dda24709ddc9106", + "sha256:90df07db7b599fe7035d2f74ab7e438b656528c68ba6bb59b7dc46af39ee48ef", + "sha256:9bb0189011785ea794ee827b68777db3ca3f93f3e339ea4d920315a0e5a78d54", + "sha256:a0e47eda4eb2614300fc7bb4657fced3e83d6334d03da2173b09e447418d499f", + "sha256:abc9d838f93583650c35eca41cfcec65b2e7cb50fd486da6f0c49b5e1ed23014", + "sha256:ac24233e8f2939ac4fd2919eed1e9c0871eac8057666070e94cbf0b33dd9c338", + "sha256:b12ba985837e4899b762b81f5b2845bd1a28f4fdd1a126d9ace64e9c4eb2fb25", + "sha256:b7a2a253d3b36d90c8993b4620183b55665a429da8357a4f621e78cd48b2b30b", + "sha256:c7064120a59ce6f64103c9cefba8ffe6fba87f2c61d67c401186423c9a20fd35", + "sha256:c89ee9314ef48c72fe92ce55c4e95f2f39d70208f9f1d9db4e64079420d8d732", + "sha256:cc4ccdc64e3039fc303defd119658148f2349239871db72cd74e2eeaa9b80b71", + "sha256:ce1edd9f5383b504dbc26eeea404ed0a00656c526638129028b758fd43fc5f10", + "sha256:ecd79298550cba13a43c340581a3ec9c707bd895a6a061a78fa2524660482fc0", + "sha256:f51c4c869d4b60d769f7b4406eec39596648d9d70246428745a681c327a8ad30", + "sha256:fb44f53af0a62dc80bba4443d9b27f2fde6acfdac281d95bc872dc148a6509cc" ], "markers": "python_version >= '3.9'", - "version": "==3.8.2" + "version": "==3.8.4" }, "mccabe": { "hashes": [ @@ -1169,24 +1307,24 @@ }, "nh3": { "hashes": [ - "sha256:0d02d0ff79dfd8208ed25a39c12cbda092388fff7f1662466e27d97ad011b770", - "sha256:3277481293b868b2715907310c7be0f1b9d10491d5adf9fce11756a97e97eddf", - "sha256:3b803a5875e7234907f7d64777dfde2b93db992376f3d6d7af7f3bc347deb305", - "sha256:427fecbb1031db085eaac9931362adf4a796428ef0163070c484b5a768e71601", - "sha256:5f0d77272ce6d34db6c87b4f894f037d55183d9518f948bba236fe81e2bb4e28", - "sha256:60684857cfa8fdbb74daa867e5cad3f0c9789415aba660614fe16cd66cbb9ec7", - "sha256:6f42f99f0cf6312e470b6c09e04da31f9abaadcd3eb591d7d1a88ea931dca7f3", - "sha256:86e447a63ca0b16318deb62498db4f76fc60699ce0a1231262880b38b6cff911", - "sha256:8d595df02413aa38586c24811237e95937ef18304e108b7e92c890a06793e3bf", - "sha256:9c0d415f6b7f2338f93035bba5c0d8c1b464e538bfbb1d598acd47d7969284f0", - "sha256:a5167a6403d19c515217b6bcaaa9be420974a6ac30e0da9e84d4fc67a5d474c5", - "sha256:ac19c0d68cd42ecd7ead91a3a032fdfff23d29302dbb1311e641a130dfefba97", - "sha256:b1e97221cedaf15a54f5243f2c5894bb12ca951ae4ddfd02a9d4ea9df9e1a29d", - "sha256:bc2d086fb540d0fa52ce35afaded4ea526b8fc4d3339f783db55c95de40ef02e", - "sha256:d1e30ff2d8d58fb2a14961f7aac1bbb1c51f9bdd7da727be35c63826060b0bf3", - "sha256:f3b53ba93bb7725acab1e030bc2ecd012a817040fd7851b332f86e2f9bb98dc6" - ], - "version": "==0.2.15" + "sha256:0316c25b76289cf23be6b66c77d3608a4fdf537b35426280032f432f14291b9a", + "sha256:1a814dd7bba1cb0aba5bcb9bebcc88fd801b63e21e2450ae6c52d3b3336bc911", + "sha256:1aa52a7def528297f256de0844e8dd680ee279e79583c76d6fa73a978186ddfb", + "sha256:22c26e20acbb253a5bdd33d432a326d18508a910e4dcf9a3316179860d53345a", + "sha256:40015514022af31975c0b3bca4014634fa13cb5dc4dbcbc00570acc781316dcc", + "sha256:40d0741a19c3d645e54efba71cb0d8c475b59135c1e3c580f879ad5514cbf028", + "sha256:551672fd71d06cd828e282abdb810d1be24e1abb7ae2543a8fa36a71c1006fe9", + "sha256:66f17d78826096291bd264f260213d2b3905e3c7fae6dfc5337d49429f1dc9f3", + "sha256:85cdbcca8ef10733bd31f931956f7fbb85145a4d11ab9e6742bbf44d88b7e351", + "sha256:a3f55fabe29164ba6026b5ad5c3151c314d136fd67415a17660b4aaddacf1b10", + "sha256:b4427ef0d2dfdec10b641ed0bdaf17957eb625b2ec0ea9329b3d28806c153d71", + "sha256:ba73a2f8d3a1b966e9cdba7b211779ad8a2561d2dba9674b8a19ed817923f65f", + "sha256:c21bac1a7245cbd88c0b0e4a420221b7bfa838a2814ee5bb924e9c2f10a1120b", + "sha256:c551eb2a3876e8ff2ac63dff1585236ed5dfec5ffd82216a7a174f7c5082a78a", + "sha256:c790769152308421283679a142dbdb3d1c46c79c823008ecea8e8141db1a2062", + "sha256:d7a25fd8c86657f5d9d576268e3b3767c5cd4f42867c9383618be8517f0f022a" + ], + "version": "==0.2.17" }, "numpy": { "hashes": [ @@ -1222,13 +1360,18 @@ "index": "pypi", "version": "==0.9.1" }, + "opentrons-shared-data": { + "editable": true, + "markers": "python_version >= '3.8'", + "path": "../shared-data/python" + }, "packaging": { "hashes": [ - "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", - "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" + "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", + "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9" ], "markers": "python_version >= '3.7'", - "version": "==23.2" + "version": "==24.0" }, "pathspec": { "hashes": [ @@ -1238,87 +1381,92 @@ "markers": "python_version >= '3.8'", "version": "==0.12.1" }, + "performance-metrics": { + "editable": true, + "file": "../performance-metrics" + }, "pillow": { "hashes": [ - "sha256:0304004f8067386b477d20a518b50f3fa658a28d44e4116970abfcd94fac34a8", - "sha256:0689b5a8c5288bc0504d9fcee48f61a6a586b9b98514d7d29b840143d6734f39", - "sha256:0eae2073305f451d8ecacb5474997c08569fb4eb4ac231ffa4ad7d342fdc25ac", - "sha256:0fb3e7fc88a14eacd303e90481ad983fd5b69c761e9e6ef94c983f91025da869", - "sha256:11fa2e5984b949b0dd6d7a94d967743d87c577ff0b83392f17cb3990d0d2fd6e", - "sha256:127cee571038f252a552760076407f9cff79761c3d436a12af6000cd182a9d04", - "sha256:154e939c5f0053a383de4fd3d3da48d9427a7e985f58af8e94d0b3c9fcfcf4f9", - "sha256:15587643b9e5eb26c48e49a7b33659790d28f190fc514a322d55da2fb5c2950e", - "sha256:170aeb00224ab3dc54230c797f8404507240dd868cf52066f66a41b33169bdbe", - "sha256:1b5e1b74d1bd1b78bc3477528919414874748dd363e6272efd5abf7654e68bef", - "sha256:1da3b2703afd040cf65ec97efea81cfba59cdbed9c11d8efc5ab09df9509fc56", - "sha256:1e23412b5c41e58cec602f1135c57dfcf15482013ce6e5f093a86db69646a5aa", - "sha256:2247178effb34a77c11c0e8ac355c7a741ceca0a732b27bf11e747bbc950722f", - "sha256:257d8788df5ca62c980314053197f4d46eefedf4e6175bc9412f14412ec4ea2f", - "sha256:3031709084b6e7852d00479fd1d310b07d0ba82765f973b543c8af5061cf990e", - "sha256:322209c642aabdd6207517e9739c704dc9f9db943015535783239022002f054a", - "sha256:322bdf3c9b556e9ffb18f93462e5f749d3444ce081290352c6070d014c93feb2", - "sha256:33870dc4653c5017bf4c8873e5488d8f8d5f8935e2f1fb9a2208c47cdd66efd2", - "sha256:35bb52c37f256f662abdfa49d2dfa6ce5d93281d323a9af377a120e89a9eafb5", - "sha256:3c31822339516fb3c82d03f30e22b1d038da87ef27b6a78c9549888f8ceda39a", - "sha256:3eedd52442c0a5ff4f887fab0c1c0bb164d8635b32c894bc1faf4c618dd89df2", - "sha256:3ff074fc97dd4e80543a3e91f69d58889baf2002b6be64347ea8cf5533188213", - "sha256:47c0995fc4e7f79b5cfcab1fc437ff2890b770440f7696a3ba065ee0fd496563", - "sha256:49d9ba1ed0ef3e061088cd1e7538a0759aab559e2e0a80a36f9fd9d8c0c21591", - "sha256:51f1a1bffc50e2e9492e87d8e09a17c5eea8409cda8d3f277eb6edc82813c17c", - "sha256:52a50aa3fb3acb9cf7213573ef55d31d6eca37f5709c69e6858fe3bc04a5c2a2", - "sha256:54f1852cd531aa981bc0965b7d609f5f6cc8ce8c41b1139f6ed6b3c54ab82bfb", - "sha256:609448742444d9290fd687940ac0b57fb35e6fd92bdb65386e08e99af60bf757", - "sha256:69ffdd6120a4737710a9eee73e1d2e37db89b620f702754b8f6e62594471dee0", - "sha256:6fad5ff2f13d69b7e74ce5b4ecd12cc0ec530fcee76356cac6742785ff71c452", - "sha256:7049e301399273a0136ff39b84c3678e314f2158f50f517bc50285fb5ec847ad", - "sha256:70c61d4c475835a19b3a5aa42492409878bbca7438554a1f89d20d58a7c75c01", - "sha256:716d30ed977be8b37d3ef185fecb9e5a1d62d110dfbdcd1e2a122ab46fddb03f", - "sha256:753cd8f2086b2b80180d9b3010dd4ed147efc167c90d3bf593fe2af21265e5a5", - "sha256:773efe0603db30c281521a7c0214cad7836c03b8ccff897beae9b47c0b657d61", - "sha256:7823bdd049099efa16e4246bdf15e5a13dbb18a51b68fa06d6c1d4d8b99a796e", - "sha256:7c8f97e8e7a9009bcacbe3766a36175056c12f9a44e6e6f2d5caad06dcfbf03b", - "sha256:823ef7a27cf86df6597fa0671066c1b596f69eba53efa3d1e1cb8b30f3533068", - "sha256:8373c6c251f7ef8bda6675dd6d2b3a0fcc31edf1201266b5cf608b62a37407f9", - "sha256:83b2021f2ade7d1ed556bc50a399127d7fb245e725aa0113ebd05cfe88aaf588", - "sha256:870ea1ada0899fd0b79643990809323b389d4d1d46c192f97342eeb6ee0b8483", - "sha256:8d12251f02d69d8310b046e82572ed486685c38f02176bd08baf216746eb947f", - "sha256:9c23f307202661071d94b5e384e1e1dc7dfb972a28a2310e4ee16103e66ddb67", - "sha256:9d189550615b4948f45252d7f005e53c2040cea1af5b60d6f79491a6e147eef7", - "sha256:a086c2af425c5f62a65e12fbf385f7c9fcb8f107d0849dba5839461a129cf311", - "sha256:a2b56ba36e05f973d450582fb015594aaa78834fefe8dfb8fcd79b93e64ba4c6", - "sha256:aebb6044806f2e16ecc07b2a2637ee1ef67a11840a66752751714a0d924adf72", - "sha256:b1b3020d90c2d8e1dae29cf3ce54f8094f7938460fb5ce8bc5c01450b01fbaf6", - "sha256:b4b6b1e20608493548b1f32bce8cca185bf0480983890403d3b8753e44077129", - "sha256:b6f491cdf80ae540738859d9766783e3b3c8e5bd37f5dfa0b76abdecc5081f13", - "sha256:b792a349405fbc0163190fde0dc7b3fef3c9268292586cf5645598b48e63dc67", - "sha256:b7c2286c23cd350b80d2fc9d424fc797575fb16f854b831d16fd47ceec078f2c", - "sha256:babf5acfede515f176833ed6028754cbcd0d206f7f614ea3447d67c33be12516", - "sha256:c365fd1703040de1ec284b176d6af5abe21b427cb3a5ff68e0759e1e313a5e7e", - "sha256:c4225f5220f46b2fde568c74fca27ae9771536c2e29d7c04f4fb62c83275ac4e", - "sha256:c570f24be1e468e3f0ce7ef56a89a60f0e05b30a3669a459e419c6eac2c35364", - "sha256:c6dafac9e0f2b3c78df97e79af707cdc5ef8e88208d686a4847bab8266870023", - "sha256:c8de2789052ed501dd829e9cae8d3dcce7acb4777ea4a479c14521c942d395b1", - "sha256:cb28c753fd5eb3dd859b4ee95de66cc62af91bcff5db5f2571d32a520baf1f04", - "sha256:cb4c38abeef13c61d6916f264d4845fab99d7b711be96c326b84df9e3e0ff62d", - "sha256:d1b35bcd6c5543b9cb547dee3150c93008f8dd0f1fef78fc0cd2b141c5baf58a", - "sha256:d8e6aeb9201e655354b3ad049cb77d19813ad4ece0df1249d3c793de3774f8c7", - "sha256:d8ecd059fdaf60c1963c58ceb8997b32e9dc1b911f5da5307aab614f1ce5c2fb", - "sha256:da2b52b37dad6d9ec64e653637a096905b258d2fc2b984c41ae7d08b938a67e4", - "sha256:e87f0b2c78157e12d7686b27d63c070fd65d994e8ddae6f328e0dcf4a0cd007e", - "sha256:edca80cbfb2b68d7b56930b84a0e45ae1694aeba0541f798e908a49d66b837f1", - "sha256:f379abd2f1e3dddb2b61bc67977a6b5a0a3f7485538bcc6f39ec76163891ee48", - "sha256:fe4c15f6c9285dc54ce6553a3ce908ed37c8f3825b5a51a15c91442bb955b868" + "sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c", + "sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2", + "sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb", + "sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d", + "sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa", + "sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3", + "sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1", + "sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a", + "sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd", + "sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8", + "sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999", + "sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599", + "sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936", + "sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375", + "sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d", + "sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b", + "sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60", + "sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572", + "sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3", + "sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced", + "sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f", + "sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b", + "sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19", + "sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f", + "sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d", + "sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383", + "sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795", + "sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355", + "sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57", + "sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09", + "sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b", + "sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462", + "sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf", + "sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f", + "sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a", + "sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad", + "sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9", + "sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d", + "sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45", + "sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994", + "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d", + "sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338", + "sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463", + "sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451", + "sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591", + "sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c", + "sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd", + "sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32", + "sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9", + "sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf", + "sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5", + "sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828", + "sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3", + "sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5", + "sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2", + "sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b", + "sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2", + "sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475", + "sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3", + "sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb", + "sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef", + "sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015", + "sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002", + "sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170", + "sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84", + "sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57", + "sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f", + "sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27", + "sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a" ], "markers": "python_version >= '3.8'", - "version": "==10.2.0" + "version": "==10.3.0" }, "pkginfo": { "hashes": [ - "sha256:4b7a555a6d5a22169fcc9cf7bfd78d296b0361adad412a346c1226849af5e546", - "sha256:8fd5896e8718a4372f0ea9cc9d96f6417c9b986e23a4d116dda26b62cc29d046" + "sha256:5df73835398d10db79f8eecd5cd86b1f6d29317589ea70796994d49399af6297", + "sha256:889a6da2ed7ffc58ab5b900d888ddce90bce912f2d2de1dc1c26f4cb9fe65097" ], "markers": "python_version >= '3.6'", - "version": "==1.9.6" + "version": "==1.10.0" }, "platformdirs": { "hashes": [ @@ -1352,6 +1500,57 @@ "markers": "python_version >= '3.8'", "version": "==2.11.1" }, + "pycparser": { + "hashes": [ + "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", + "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc" + ], + "markers": "python_version >= '3.8'", + "version": "==2.22" + }, + "pydantic": { + "hashes": [ + "sha256:0fe8a415cea8f340e7a9af9c54fc71a649b43e8ca3cc732986116b3cb135d303", + "sha256:1289c180abd4bd4555bb927c42ee42abc3aee02b0fb2d1223fb7c6e5bef87dbe", + "sha256:1eb2085c13bce1612da8537b2d90f549c8cbb05c67e8f22854e201bde5d98a47", + "sha256:2031de0967c279df0d8a1c72b4ffc411ecd06bac607a212892757db7462fc494", + "sha256:2a7bac939fa326db1ab741c9d7f44c565a1d1e80908b3797f7f81a4f86bc8d33", + "sha256:2d5a58feb9a39f481eda4d5ca220aa8b9d4f21a41274760b9bc66bfd72595b86", + "sha256:2f9a6fab5f82ada41d56b0602606a5506aab165ca54e52bc4545028382ef1c5d", + "sha256:2fcfb5296d7877af406ba1547dfde9943b1256d8928732267e2653c26938cd9c", + "sha256:549a8e3d81df0a85226963611950b12d2d334f214436a19537b2efed61b7639a", + "sha256:598da88dfa127b666852bef6d0d796573a8cf5009ffd62104094a4fe39599565", + "sha256:5d1197e462e0364906cbc19681605cb7c036f2475c899b6f296104ad42b9f5fb", + "sha256:69328e15cfda2c392da4e713443c7dbffa1505bc9d566e71e55abe14c97ddc62", + "sha256:6a9dfa722316f4acf4460afdf5d41d5246a80e249c7ff475c43a3a1e9d75cf62", + "sha256:6b30bcb8cbfccfcf02acb8f1a261143fab622831d9c0989707e0e659f77a18e0", + "sha256:6c076be61cd0177a8433c0adcb03475baf4ee91edf5a4e550161ad57fc90f523", + "sha256:771735dc43cf8383959dc9b90aa281f0b6092321ca98677c5fb6125a6f56d58d", + "sha256:795e34e6cc065f8f498c89b894a3c6da294a936ee71e644e4bd44de048af1405", + "sha256:87afda5539d5140cb8ba9e8b8c8865cb5b1463924d38490d73d3ccfd80896b3f", + "sha256:8fb2aa3ab3728d950bcc885a2e9eff6c8fc40bc0b7bb434e555c215491bcf48b", + "sha256:a1fcb59f2f355ec350073af41d927bf83a63b50e640f4dbaa01053a28b7a7718", + "sha256:a5e7add47a5b5a40c49b3036d464e3c7802f8ae0d1e66035ea16aa5b7a3923ed", + "sha256:a73f489aebd0c2121ed974054cb2759af8a9f747de120acd2c3394cf84176ccb", + "sha256:ab26038b8375581dc832a63c948f261ae0aa21f1d34c1293469f135fa92972a5", + "sha256:b0d191db0f92dfcb1dec210ca244fdae5cbe918c6050b342d619c09d31eea0cc", + "sha256:b749a43aa51e32839c9d71dc67eb1e4221bb04af1033a32e3923d46f9effa942", + "sha256:b7ccf02d7eb340b216ec33e53a3a629856afe1c6e0ef91d84a4e6f2fb2ca70fe", + "sha256:ba5b2e6fe6ca2b7e013398bc7d7b170e21cce322d266ffcd57cca313e54fb246", + "sha256:ba5c4a8552bff16c61882db58544116d021d0b31ee7c66958d14cf386a5b5350", + "sha256:c79e6a11a07da7374f46970410b41d5e266f7f38f6a17a9c4823db80dadf4303", + "sha256:ca48477862372ac3770969b9d75f1bf66131d386dba79506c46d75e6b48c1e09", + "sha256:dea7adcc33d5d105896401a1f37d56b47d443a2b2605ff8a969a0ed5543f7e33", + "sha256:e0a16d274b588767602b7646fa05af2782576a6cf1022f4ba74cbb4db66f6ca8", + "sha256:e4129b528c6baa99a429f97ce733fff478ec955513630e61b49804b6cf9b224a", + "sha256:e5f805d2d5d0a41633651a73fa4ecdd0b3d7a49de4ec3fadf062fe16501ddbf1", + "sha256:ef6c96b2baa2100ec91a4b428f80d8f28a3c9e53568219b6c298c1125572ebc6", + "sha256:fdbdd1d630195689f325c9ef1a12900524dceb503b00a987663ff4f58669b93d" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==1.10.12" + }, "pydocstyle": { "hashes": [ "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019", @@ -1378,11 +1577,49 @@ }, "pyparsing": { "hashes": [ - "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb", - "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db" + "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad", + "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742" ], "markers": "python_full_version >= '3.6.8'", - "version": "==3.1.1" + "version": "==3.1.2" + }, + "pyrsistent": { + "hashes": [ + "sha256:0724c506cd8b63c69c7f883cc233aac948c1ea946ea95996ad8b1380c25e1d3f", + "sha256:09848306523a3aba463c4b49493a760e7a6ca52e4826aa100ee99d8d39b7ad1e", + "sha256:0f3b1bcaa1f0629c978b355a7c37acd58907390149b7311b5db1b37648eb6958", + "sha256:21cc459636983764e692b9eba7144cdd54fdec23ccdb1e8ba392a63666c60c34", + "sha256:2e14c95c16211d166f59c6611533d0dacce2e25de0f76e4c140fde250997b3ca", + "sha256:2e2c116cc804d9b09ce9814d17df5edf1df0c624aba3b43bc1ad90411487036d", + "sha256:4021a7f963d88ccd15b523787d18ed5e5269ce57aa4037146a2377ff607ae87d", + "sha256:4c48f78f62ab596c679086084d0dd13254ae4f3d6c72a83ffdf5ebdef8f265a4", + "sha256:4f5c2d012671b7391803263419e31b5c7c21e7c95c8760d7fc35602353dee714", + "sha256:58b8f6366e152092194ae68fefe18b9f0b4f89227dfd86a07770c3d86097aebf", + "sha256:59a89bccd615551391f3237e00006a26bcf98a4d18623a19909a2c48b8e986ee", + "sha256:5cdd7ef1ea7a491ae70d826b6cc64868de09a1d5ff9ef8d574250d0940e275b8", + "sha256:6288b3fa6622ad8a91e6eb759cfc48ff3089e7c17fb1d4c59a919769314af224", + "sha256:6d270ec9dd33cdb13f4d62c95c1a5a50e6b7cdd86302b494217137f760495b9d", + "sha256:79ed12ba79935adaac1664fd7e0e585a22caa539dfc9b7c7c6d5ebf91fb89054", + "sha256:7d29c23bdf6e5438c755b941cef867ec2a4a172ceb9f50553b6ed70d50dfd656", + "sha256:8441cf9616d642c475684d6cf2520dd24812e996ba9af15e606df5f6fd9d04a7", + "sha256:881bbea27bbd32d37eb24dd320a5e745a2a5b092a17f6debc1349252fac85423", + "sha256:8c3aba3e01235221e5b229a6c05f585f344734bd1ad42a8ac51493d74722bbce", + "sha256:a14798c3005ec892bbada26485c2eea3b54109cb2533713e355c806891f63c5e", + "sha256:b14decb628fac50db5e02ee5a35a9c0772d20277824cfe845c8a8b717c15daa3", + "sha256:b318ca24db0f0518630e8b6f3831e9cba78f099ed5c1d65ffe3e023003043ba0", + "sha256:c1beb78af5423b879edaf23c5591ff292cf7c33979734c99aa66d5914ead880f", + "sha256:c55acc4733aad6560a7f5f818466631f07efc001fd023f34a6c203f8b6df0f0b", + "sha256:ca52d1ceae015859d16aded12584c59eb3825f7b50c6cfd621d4231a6cc624ce", + "sha256:cae40a9e3ce178415040a0383f00e8d68b569e97f31928a3a8ad37e3fde6df6a", + "sha256:e78d0c7c1e99a4a45c99143900ea0546025e41bb59ebc10182e947cf1ece9174", + "sha256:ef3992833fbd686ee783590639f4b8343a57f1f75de8633749d984dc0eb16c86", + "sha256:f058a615031eea4ef94ead6456f5ec2026c19fb5bd6bfe86e9665c4158cf802f", + "sha256:f5ac696f02b3fc01a710427585c855f65cd9c640e14f52abe52020722bb4906b", + "sha256:f920385a11207dc372a028b3f1e1038bb244b3ec38d448e6d8e43c6b3ba20e98", + "sha256:fed2c3216a605dc9a6ea50c7e84c82906e3684c4e80d2908208f662a6cbf9022" + ], + "markers": "python_version >= '3.8'", + "version": "==0.20.0" }, "pytest": { "hashes": [ @@ -1395,12 +1632,12 @@ }, "pytest-asyncio": { "hashes": [ - "sha256:2143d9d9375bf372a73260e4114541485e84fca350b0b6b92674ca56ff5f7ea2", - "sha256:b0079dfac14b60cd1ce4691fbfb1748fe939db7d0234b5aba97197d10fbe0fef" + "sha256:68516fdd1018ac57b846c9846b954f0393b26f094764a28c955eabb0536a4e8a", + "sha256:ffe523a89c1c222598c76856e76852b787504ddb72dd5d9b6617ffa8aa2cde5f" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==0.23.4" + "version": "==0.23.6" }, "pytest-cov": { "hashes": [ @@ -1448,19 +1685,19 @@ }, "python-dateutil": { "hashes": [ - "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", - "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" + "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", + "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.8.2" + "version": "==2.9.0.post0" }, "readme-renderer": { "hashes": [ - "sha256:13d039515c1f24de668e2c93f2e877b9dbe6c6c32328b90a40a49d8b2b85f36d", - "sha256:2d55489f83be4992fe4454939d1a051c33edbab778e82761d060c9fc6b308cd1" + "sha256:1818dd28140813509eeed8d62687f7cd4f7bad90d4db586001c5dc09d4fde311", + "sha256:19db308d86ecd60e5affa3b2a98f017af384678c63c88e5d4556a380e674f3f9" ], "markers": "python_version >= '3.8'", - "version": "==42.0" + "version": "==43.0" }, "requests": { "hashes": [ @@ -1488,11 +1725,19 @@ }, "rich": { "hashes": [ - "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa", - "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235" + "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222", + "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432" ], "markers": "python_full_version >= '3.7.0'", - "version": "==13.7.0" + "version": "==13.7.1" + }, + "secretstorage": { + "hashes": [ + "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77", + "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99" + ], + "markers": "sys_platform == 'linux'", + "version": "==3.3.3" }, "six": { "hashes": [ @@ -1633,12 +1878,12 @@ }, "types-mock": { "hashes": [ - "sha256:13ca379d5710ccb3f18f69ade5b08881874cb83383d8fb49b1d4dac9d5c5d090", - "sha256:3d116955495935b0bcba14954b38d97e507cd43eca3e3700fc1b8e4f5c6bf2c7" + "sha256:0769cb376dfc75b45215619f17a9fd6333d771cc29ce4a38937f060b1e45530f", + "sha256:7472797986d83016f96fde7f73577d129b0cd8a8d0b783487a7be330d57ba431" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==5.1.0.20240106" + "version": "==5.1.0.20240311" }, "types-setuptools": { "hashes": [ @@ -1650,19 +1895,19 @@ }, "typing-extensions": { "hashes": [ - "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", - "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0", + "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a" ], "markers": "python_version >= '3.8'", - "version": "==4.9.0" + "version": "==4.11.0" }, "urllib3": { "hashes": [ - "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20", - "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224" + "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", + "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19" ], "markers": "python_version >= '3.8'", - "version": "==2.2.0" + "version": "==2.2.1" }, "wheel": { "hashes": [ @@ -1675,11 +1920,11 @@ }, "zipp": { "hashes": [ - "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31", - "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0" + "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b", + "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715" ], "markers": "python_version >= '3.8'", - "version": "==3.17.0" + "version": "==3.18.1" } } } diff --git a/api/docs/v2/index.rst b/api/docs/v2/index.rst index 376d483f33b..5e29296241d 100644 --- a/api/docs/v2/index.rst +++ b/api/docs/v2/index.rst @@ -171,17 +171,17 @@ More Resources Opentrons App +++++++++++++ -The `Opentrons App `__ is the easiest way to run your Python protocols. The app `supports `_ the latest versions of macOS, Windows, and Ubuntu. +The `Opentrons App `__ is the easiest way to run your Python protocols. The app runs on the latest versions of macOS, Windows, and Ubuntu. Support +++++++ -Questions about setting up your robot, using Opentrons software, or troubleshooting? Check out our `support articles `_ or `get in touch directly `_ with Opentrons Support. +Questions about setting up your robot, using Opentrons software, or troubleshooting? Check out our `support articles `_ or `contact Opentrons Support directly `_. Custom Protocol Service +++++++++++++++++++++++ -Don't have the time or resources to write your own protocols? The `Opentrons Custom Protocols `_ service can get you set up in as little as a week. +Don't have the time or resources to write your own protocols? Our `custom protocol development service `_ can get you set up in two weeks. Contributing ++++++++++++ diff --git a/api/release-notes-internal.md b/api/release-notes-internal.md index f05cd2e2f1e..353df2e8833 100644 --- a/api/release-notes-internal.md +++ b/api/release-notes-internal.md @@ -2,6 +2,48 @@ For more details about this release, please see the full [technical change log][ [technical change log]: https://github.com/Opentrons/opentrons/releases +## Internal Release 1.5.0-alpha.1 + +This internal release is from the `edge` branch to contain rapid dev on new features for 7.3.0. This release is for internal testing purposes and if used may require a factory reset of the robot to return to a stable version. + + + +--- + +## Internal Release 1.5.0-alpha.0 + +This internal release is from the `edge` branch to contain rapid dev on new features for 7.3.0. This release is for internal testing purposes and if used may require a factory reset of the robot to return to a stable version. + + + +--- + +## Internal Release 1.4.0-alpha.1 + +This internal release is from the `edge` branch to contain rapid dev on new features for 7.3.0. This release is for internal testing purposes and if used may require a factory reset of the robot to return to a stable version. + +This release is primarily to unblock Flex runs. That fix is in + +### All changes + + + +--- + +## Internal Release 1.4.0-alpha.0 + +This internal release is from the `edge` branch to contain rapid dev on new features for 7.3.0. This release is for internal testing purposes and if used may require a factory reset of the robot to return to a stable version. + + + +--- + +## Internal Release 1.3.0-alpha.0 + +This internal release is from the `edge` branch to contain rapid dev on new features for 7.3.0. This release is for internal testing purposes and if used may require a factory reset of the robot to return to a stable version. + + + --- # Internal Release 1.1.0 diff --git a/api/release-notes.md b/api/release-notes.md index ff193247459..737b4063c9c 100644 --- a/api/release-notes.md +++ b/api/release-notes.md @@ -6,6 +6,46 @@ log][]. For a list of currently known issues, please see the [Opentrons issue tr --- +## Opentrons Robot Software Changes in 7.3.0 + +Welcome to the v7.3.0 release of the Opentrons robot software! + +### New Features + +- Runtime parameters: read, write, and use parameters in Python protocol runs. + +### Improved Features + +- Automatic tip tracking is now available for all nozzle configurations. +- Flex no longer shows unnecessary pipette calibration warnings. +- Python protocols can once again set labware offsets outside of Labware Position Check. + +### Changed Features + +- Calling `GET /runs/{id}/commands` for a JSON protocol no longer returns a full list of queued commands. Use protocol analysis to get a full list of commands. + +### Bug Fixes + +- Fixed an edge case where capitalizing part of a labware load name could cause unexpected behavior or collisions. +- Fixed Python packages installed on the OT-2 with `pip` not being found by `import` statements. + +--- + +## Opentrons Robot Software Changes in 7.2.2 + +Welcome to the v7.2.2 release of the Opentrons robot software! + +### Improved Features + +- Improved the low-volume performance of recently produced Flex 96-Channel Pipettes. + +### Bug Fixes + +- Restores the ability to use the speaker and camera on OT-2. +- Restores the ability to use the camera on Flex. + +--- + ## Opentrons Robot Software Changes in 7.2.1 Welcome to the v7.2.1 release of the Opentrons robot software! diff --git a/api/setup.py b/api/setup.py index ae53321ca22..1811b6b4e2d 100755 --- a/api/setup.py +++ b/api/setup.py @@ -46,8 +46,6 @@ def get_version(): "Intended Audience :: Science/Research", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Topic :: Scientific/Engineering", ] @@ -87,7 +85,7 @@ def read(*parts): if __name__ == "__main__": setup( - python_requires=">=3.8", + python_requires=">=3.10", name=DISTNAME, description=DESCRIPTION, license=LICENSE, diff --git a/api/src/opentrons/calibration_storage/deck_configuration.py b/api/src/opentrons/calibration_storage/deck_configuration.py index 31410403d35..a627fce73c9 100644 --- a/api/src/opentrons/calibration_storage/deck_configuration.py +++ b/api/src/opentrons/calibration_storage/deck_configuration.py @@ -10,6 +10,7 @@ class _CutoutFixturePlacementModel(pydantic.BaseModel): cutoutId: str cutoutFixtureId: str + opentronsModuleSerialNumber: Optional[str] class _DeckConfigurationModel(pydantic.BaseModel): @@ -26,7 +27,9 @@ def serialize_deck_configuration( data = _DeckConfigurationModel.construct( cutoutFixtures=[ _CutoutFixturePlacementModel.construct( - cutoutId=e.cutout_id, cutoutFixtureId=e.cutout_fixture_id + cutoutId=e.cutout_id, + cutoutFixtureId=e.cutout_fixture_id, + opentronsModuleSerialNumber=e.opentrons_module_serial_number, ) for e in cutout_fixture_placements ], @@ -50,7 +53,9 @@ def deserialize_deck_configuration( else: cutout_fixture_placements = [ CutoutFixturePlacement( - cutout_id=e.cutoutId, cutout_fixture_id=e.cutoutFixtureId + cutout_id=e.cutoutId, + cutout_fixture_id=e.cutoutFixtureId, + opentrons_module_serial_number=e.opentronsModuleSerialNumber, ) for e in parsed.cutoutFixtures ] diff --git a/api/src/opentrons/calibration_storage/types.py b/api/src/opentrons/calibration_storage/types.py index fd1bfbd5e2e..bd80af33719 100644 --- a/api/src/opentrons/calibration_storage/types.py +++ b/api/src/opentrons/calibration_storage/types.py @@ -42,3 +42,4 @@ class UriDetails: class CutoutFixturePlacement: cutout_fixture_id: str cutout_id: str + opentrons_module_serial_number: typing.Optional[str] diff --git a/api/src/opentrons/cli/analyze.py b/api/src/opentrons/cli/analyze.py index a42a4f5f868..96784a340d7 100644 --- a/api/src/opentrons/cli/analyze.py +++ b/api/src/opentrons/cli/analyze.py @@ -1,12 +1,27 @@ """Opentrons analyze CLI.""" import click -from anyio import run, Path as AsyncPath +from anyio import run +from contextlib import contextmanager +from dataclasses import dataclass from datetime import datetime, timezone from pathlib import Path from pydantic import BaseModel -from typing import Any, Dict, List, Optional, Sequence, Union -from typing_extensions import Literal +from typing import ( + Any, + Dict, + List, + Optional, + Sequence, + Union, + Literal, + Callable, + IO, + TypeVar, + Iterator, +) +import logging +import sys from opentrons.protocol_engine.types import RunTimeParameter from opentrons.protocols.api_support.types import APIVersion @@ -16,8 +31,9 @@ ProtocolType, JsonProtocolConfig, ProtocolFilesInvalidError, + ProtocolSource, ) -from opentrons.protocol_runner import create_simulating_runner +from opentrons.protocol_runner import create_simulating_runner, RunResult from opentrons.protocol_engine import ( Command, ErrorOccurrence, @@ -28,6 +44,15 @@ ) from opentrons_shared_data.robot.dev_types import RobotType +from opentrons.util.performance_helpers import track_analysis + +OutputKind = Literal["json", "human-json"] + + +@dataclass(frozen=True) +class _Output: + to_file: IO[bytes] + kind: OutputKind @click.command() @@ -39,16 +64,108 @@ ) @click.option( "--json-output", - help="Return analysis results as machine-readable JSON.", - type=click.Path(path_type=AsyncPath), + help="Return analysis results as machine-readable JSON. Specify --json-output=- to use stdout, but be aware that Python protocols may contain print() which will make the output JSON invalid.", + type=click.File(mode="wb"), +) +@click.option( + "--human-json-output", + help="Return analysis results as JSON, formatted for human eyes. Specify --human-json-output=- to use stdout, but be aware that Python protocols may contain print() which will make the output JSON invalid.", + type=click.File(mode="wb"), +) +@click.option( + "--check", + help="Fail (via exit code) if the protocol had an error. If not specified, always succeed.", + is_flag=True, + default=False, +) +@click.option( + "--log-output", + help="Where to send logs. Can be a path, - for stdout, or stderr for stderr.", + default="stderr", + type=str, +) +@click.option( + "--log-level", + help="Level of logs to capture.", + type=click.Choice(["DEBUG", "INFO", "WARNING", "ERROR"], case_sensitive=False), + default="WARNING", ) -def analyze(files: Sequence[Path], json_output: Optional[Path]) -> None: +def analyze( + files: Sequence[Path], + json_output: Optional[IO[bytes]], + human_json_output: Optional[IO[bytes]], + log_output: str, + log_level: str, + check: bool, +) -> int: """Analyze a protocol. You can use `opentrons analyze` to get a protocol's expected equipment and commands. """ - run(_analyze, files, json_output) + outputs = _get_outputs(json=json_output, human_json=human_json_output) + if not outputs and not check: + raise click.UsageError( + message="Please specify at least --check or one of the output options." + ) + + try: + with _capture_logs(log_output, log_level): + sys.exit(run(_analyze, files, outputs, check)) + except click.ClickException: + raise + except Exception as e: + raise click.ClickException(str(e)) + + +@contextmanager +def _capture_logs_to_stream(stream: IO[str]) -> Iterator[None]: + handler = logging.StreamHandler(stream) + logging.getLogger().addHandler(handler) + try: + yield + finally: + logging.getLogger().removeHandler(handler) + + +@contextmanager +def _capture_logs_to_file(filepath: Path) -> Iterator[None]: + handler = logging.FileHandler(filepath, mode="w") + logging.getLogger().addHandler(handler) + try: + yield + finally: + logging.getLogger().removeHandler(handler) + + +@contextmanager +def _capture_logs(write_to: str, log_level: str) -> Iterator[None]: + try: + level = getattr(logging, log_level) + except AttributeError: + raise click.ClickException(f"No such log level {log_level}") + logging.getLogger().setLevel(level) + if write_to in ("-", "stdout"): + with _capture_logs_to_stream(sys.stdout): + yield + elif write_to == "stderr": + with _capture_logs_to_stream(sys.stderr): + yield + else: + with _capture_logs_to_file(Path(write_to)): + yield + + +def _get_outputs( + json: Optional[IO[bytes]], + human_json: Optional[IO[bytes]], +) -> List[_Output]: + outputs: List[_Output] = [] + if json: + outputs.append(_Output(to_file=json, kind="json")) + if human_json: + outputs.append(_Output(to_file=human_json, kind="human-json")) + return outputs def _get_input_files(files_and_dirs: Sequence[Path]) -> List[Path]: @@ -63,12 +180,37 @@ def _get_input_files(files_and_dirs: Sequence[Path]) -> List[Path]: return results +R = TypeVar("R") + + +def _call_for_output_of_kind( + kind: OutputKind, outputs: Sequence[_Output], fn: Callable[[IO[bytes]], R] +) -> Optional[R]: + for output in outputs: + if output.kind == kind: + return fn(output.to_file) + return None + + +def _get_return_code(analysis: RunResult) -> int: + if analysis.state_summary.errors: + return -1 + return 0 + + +@track_analysis +async def _do_analyze(protocol_source: ProtocolSource) -> RunResult: + + runner = await create_simulating_runner( + robot_type=protocol_source.robot_type, protocol_config=protocol_source.config + ) + return await runner.run(deck_configuration=[], protocol_source=protocol_source) + + async def _analyze( - files_and_dirs: Sequence[Path], - json_output: Optional[AsyncPath], -) -> None: + files_and_dirs: Sequence[Path], outputs: Sequence[_Output], check: bool +) -> int: input_files = _get_input_files(files_and_dirs) - try: protocol_source = await ProtocolReader().read_saved( files=input_files, @@ -77,47 +219,52 @@ async def _analyze( except ProtocolFilesInvalidError as error: raise click.ClickException(str(error)) - runner = await create_simulating_runner( - robot_type=protocol_source.robot_type, protocol_config=protocol_source.config + analysis = await _do_analyze(protocol_source) + return_code = _get_return_code(analysis) + + if not outputs: + return return_code + + results = AnalyzeResults.construct( + createdAt=datetime.now(tz=timezone.utc), + files=[ + ProtocolFile.construct(name=f.path.name, role=f.role) + for f in protocol_source.files + ], + config=( + JsonConfig.construct(schemaVersion=protocol_source.config.schema_version) + if isinstance(protocol_source.config, JsonProtocolConfig) + else PythonConfig.construct(apiVersion=protocol_source.config.api_version) + ), + metadata=protocol_source.metadata, + robotType=protocol_source.robot_type, + runTimeParameters=analysis.parameters, + commands=analysis.commands, + errors=analysis.state_summary.errors, + labware=analysis.state_summary.labware, + pipettes=analysis.state_summary.pipettes, + modules=analysis.state_summary.modules, + liquids=analysis.state_summary.liquids, ) - analysis = await runner.run(deck_configuration=[], protocol_source=protocol_source) - - if json_output: - results = AnalyzeResults.construct( - createdAt=datetime.now(tz=timezone.utc), - files=[ - ProtocolFile.construct(name=f.path.name, role=f.role) - for f in protocol_source.files - ], - config=( - JsonConfig.construct( - schemaVersion=protocol_source.config.schema_version - ) - if isinstance(protocol_source.config, JsonProtocolConfig) - else PythonConfig.construct( - apiVersion=protocol_source.config.api_version - ) - ), - metadata=protocol_source.metadata, - robotType=protocol_source.robot_type, - runTimeParameters=analysis.parameters, - commands=analysis.commands, - errors=analysis.state_summary.errors, - labware=analysis.state_summary.labware, - pipettes=analysis.state_summary.pipettes, - modules=analysis.state_summary.modules, - liquids=analysis.state_summary.liquids, - ) - - await json_output.write_text( - results.json(exclude_none=True), - encoding="utf-8", - ) + _call_for_output_of_kind( + "json", + outputs, + lambda to_file: to_file.write( + results.json(exclude_none=True).encode("utf-8"), + ), + ) + _call_for_output_of_kind( + "human-json", + outputs, + lambda to_file: to_file.write( + results.json(exclude_none=True, indent=2).encode("utf-8") + ), + ) + if check: + return return_code else: - raise click.UsageError( - "Currently, this tool only supports JSON mode. Use `--json-output`." - ) + return 0 class ProtocolFile(BaseModel): diff --git a/api/src/opentrons/config/__init__.py b/api/src/opentrons/config/__init__.py index ce867677777..a4571521211 100644 --- a/api/src/opentrons/config/__init__.py +++ b/api/src/opentrons/config/__init__.py @@ -284,6 +284,13 @@ class ConfigElement(NamedTuple): ConfigElementType.DIR, "The dir where module calibration is stored", ), + ConfigElement( + "performance_metrics_dir", + "Performance Metrics Directory", + Path("performance_metrics_data"), + ConfigElementType.DIR, + "The dir where performance metrics are stored", + ), ) #: The available configuration file elements to modify. All of these can be #: changed by editing opentrons.json, where the keys are the name elements, @@ -602,3 +609,7 @@ def get_tip_length_cal_path() -> Path: def get_custom_tiprack_def_path() -> Path: return get_opentrons_path("custom_tiprack_dir") + + +def get_performance_metrics_data_dir() -> Path: + return get_opentrons_path("performance_metrics_dir") diff --git a/api/src/opentrons/config/advanced_settings.py b/api/src/opentrons/config/advanced_settings.py index f4c75701901..f65b5824eb1 100644 --- a/api/src/opentrons/config/advanced_settings.py +++ b/api/src/opentrons/config/advanced_settings.py @@ -159,19 +159,6 @@ class Setting(NamedTuple): robot_type=[RobotTypeEnum.OT2], default_true_on_robot_types=[RobotTypeEnum.FLEX], ), - SettingDefinition( - _id="disableFastProtocolUpload", - title="Use older protocol analysis method", - description=( - "Use an older, slower method of analyzing uploaded protocols. " - "This changes how the OT-2 validates your protocol during the upload " - "step, but does not affect how your protocol actually runs. " - "Opentrons Support might ask you to change this setting if you encounter " - "problems with the newer, faster protocol analysis method." - ), - restart_required=False, - robot_type=[RobotTypeEnum.OT2, RobotTypeEnum.FLEX], - ), SettingDefinition( _id="enableOT3HardwareController", title="Enable experimental OT-3 hardware controller", @@ -238,7 +225,6 @@ class Setting(NamedTuple): title="Enable OEM Mode", description="This setting anonymizes Opentrons branding in the ODD app.", robot_type=[RobotTypeEnum.FLEX], - internal_only=True, ), SettingDefinition( _id="enablePerformanceMetrics", @@ -730,6 +716,16 @@ def _migrate32to33(previous: SettingsMap) -> SettingsMap: return newmap +def _migrate33to34(previous: SettingsMap) -> SettingsMap: + """Migrate to version 34 of the feature flags file. + + - Removes disableFastProtocolUpload + """ + removals = ["disableFastProtocolUpload"] + newmap = {k: v for k, v in previous.items() if k not in removals} + return newmap + + _MIGRATIONS = [ _migrate0to1, _migrate1to2, @@ -764,6 +760,7 @@ def _migrate32to33(previous: SettingsMap) -> SettingsMap: _migrate30to31, _migrate31to32, _migrate32to33, + _migrate33to34, ] """ List of all migrations to apply, indexed by (version - 1). See _migrate below diff --git a/api/src/opentrons/config/defaults_ot3.py b/api/src/opentrons/config/defaults_ot3.py index cb553caaed3..a7703f9fcba 100644 --- a/api/src/opentrons/config/defaults_ot3.py +++ b/api/src/opentrons/config/defaults_ot3.py @@ -1,8 +1,8 @@ -from typing import Any, Dict, cast, List, Iterable, Tuple +from typing import Any, Dict, cast, List, Iterable, Tuple, Optional from typing_extensions import Final from dataclasses import asdict -from opentrons.hardware_control.types import OT3AxisKind +from opentrons.hardware_control.types import OT3AxisKind, InstrumentProbeType from .types import ( OT3Config, ByGantryLoad, @@ -34,7 +34,7 @@ aspirate_while_sensing=False, auto_zero_sensor=True, num_baseline_reads=10, - data_file="/var/pressure_sensor_data.csv", + data_files={InstrumentProbeType.PRIMARY: "/data/pressure_sensor_data.csv"}, ) DEFAULT_CALIBRATION_SETTINGS: Final[OT3CalibrationSettings] = OT3CalibrationSettings( @@ -198,6 +198,49 @@ ) +def _build_output_option_with_default( + from_conf: Any, default: OutputOptions +) -> OutputOptions: + if from_conf is None: + return default + else: + if isinstance(from_conf, OutputOptions): + return from_conf + else: + try: + enumval = OutputOptions[from_conf] + except KeyError: # not an enum entry + return default + else: + return enumval + + +def _build_log_files_with_default( + from_conf: Any, + default: Optional[Dict[InstrumentProbeType, str]], +) -> Optional[Dict[InstrumentProbeType, str]]: + print(f"from_conf {from_conf} default {default}") + if not isinstance(from_conf, dict): + if default is None: + return None + else: + return {k: v for k, v in default.items()} + else: + validated: Dict[InstrumentProbeType, str] = {} + for k, v in from_conf.items(): + if isinstance(k, InstrumentProbeType): + validated[k] = v + else: + try: + enumval = InstrumentProbeType[k] + except KeyError: # not an enum entry + pass + else: + validated[enumval] = v + print(f"result {validated}") + return validated + + def _build_dict_with_default( from_conf: Any, default: Dict[OT3AxisKind, float], @@ -284,6 +327,17 @@ def _build_default_cap_pass( def _build_default_liquid_probe( from_conf: Any, default: LiquidProbeSettings ) -> LiquidProbeSettings: + output_option = _build_output_option_with_default( + from_conf.get("output_option", None), default.output_option + ) + data_files: Optional[Dict[InstrumentProbeType, str]] = None + if ( + output_option is OutputOptions.sync_buffer_to_csv + or output_option is OutputOptions.stream_to_csv + ): + data_files = _build_log_files_with_default( + from_conf.get("data_files", {}), default.data_files + ) return LiquidProbeSettings( starting_mount_height=from_conf.get( "starting_mount_height", default.starting_mount_height @@ -308,7 +362,7 @@ def _build_default_liquid_probe( num_baseline_reads=from_conf.get( "num_baseline_reads", default.num_baseline_reads ), - data_file=from_conf.get("data_file", default.data_file), + data_files=data_files, ) @@ -418,7 +472,7 @@ def build_with_defaults(robot_settings: Dict[str, Any]) -> OT3Config: def serialize(config: OT3Config) -> Dict[str, Any]: def _build_dict(pairs: Iterable[Tuple[Any, Any]]) -> Dict[str, Any]: def _normalize_key(key: Any) -> Any: - if isinstance(key, OT3AxisKind): + if isinstance(key, OT3AxisKind) or isinstance(key, InstrumentProbeType): return key.name return key diff --git a/api/src/opentrons/config/feature_flags.py b/api/src/opentrons/config/feature_flags.py index e9772a01ee8..719c0dc43f3 100644 --- a/api/src/opentrons/config/feature_flags.py +++ b/api/src/opentrons/config/feature_flags.py @@ -24,12 +24,6 @@ def enable_door_safety_switch(robot_type: RobotTypeEnum) -> bool: return advs.get_setting_with_env_overload("enableDoorSafetySwitch", robot_type) -def disable_fast_protocol_upload() -> bool: - return advs.get_setting_with_env_overload( - "disableFastProtocolUpload", RobotTypeEnum.FLEX - ) - - def enable_ot3_hardware_controller() -> bool: """Get whether to use the OT-3 hardware controller.""" @@ -80,3 +74,7 @@ def enable_error_recovery_experiments() -> bool: def enable_performance_metrics(robot_type: RobotTypeEnum) -> bool: return advs.get_setting_with_env_overload("enablePerformanceMetrics", robot_type) + + +def oem_mode_enabled() -> bool: + return advs.get_setting_with_env_overload("enableOEMMode", RobotTypeEnum.FLEX) diff --git a/api/src/opentrons/config/types.py b/api/src/opentrons/config/types.py index 47bb3754cac..16cea19bafd 100644 --- a/api/src/opentrons/config/types.py +++ b/api/src/opentrons/config/types.py @@ -2,7 +2,7 @@ from dataclasses import dataclass, asdict, fields from typing import Dict, Tuple, TypeVar, Generic, List, cast, Optional from typing_extensions import TypedDict, Literal -from opentrons.hardware_control.types import OT3AxisKind +from opentrons.hardware_control.types import OT3AxisKind, InstrumentProbeType class AxisDict(TypedDict): @@ -140,7 +140,7 @@ class LiquidProbeSettings: aspirate_while_sensing: bool auto_zero_sensor: bool num_baseline_reads: int - data_file: Optional[str] + data_files: Optional[Dict[InstrumentProbeType, str]] @dataclass(frozen=True) diff --git a/api/src/opentrons/hardware_control/backends/flex_protocol.py b/api/src/opentrons/hardware_control/backends/flex_protocol.py index 45b625a3705..a0e5fcae99d 100644 --- a/api/src/opentrons/hardware_control/backends/flex_protocol.py +++ b/api/src/opentrons/hardware_control/backends/flex_protocol.py @@ -147,7 +147,7 @@ async def liquid_probe( plunger_speed: float, threshold_pascals: float, output_format: OutputOptions = OutputOptions.can_bus_only, - data_file: Optional[str] = None, + data_files: Optional[Dict[InstrumentProbeType, str]] = None, auto_zero_sensor: bool = True, num_baseline_reads: int = 10, probe: InstrumentProbeType = InstrumentProbeType.PRIMARY, @@ -385,7 +385,9 @@ async def capacitive_pass( def subsystems(self) -> Dict[SubSystem, SubSystemState]: ... - async def get_tip_status(self, mount: OT3Mount) -> TipStateType: + async def get_tip_status( + self, mount: OT3Mount, ht_operation_sensor: Optional[InstrumentProbeType] = None + ) -> TipStateType: ... def current_tip_state(self, mount: OT3Mount) -> Optional[bool]: diff --git a/api/src/opentrons/hardware_control/backends/ot3controller.py b/api/src/opentrons/hardware_control/backends/ot3controller.py index 294dc9583aa..6874b828a61 100644 --- a/api/src/opentrons/hardware_control/backends/ot3controller.py +++ b/api/src/opentrons/hardware_control/backends/ot3controller.py @@ -1351,7 +1351,7 @@ async def liquid_probe( plunger_speed: float, threshold_pascals: float, output_option: OutputOptions = OutputOptions.can_bus_only, - data_file: Optional[str] = None, + data_files: Optional[Dict[InstrumentProbeType, str]] = None, auto_zero_sensor: bool = True, num_baseline_reads: int = 10, probe: InstrumentProbeType = InstrumentProbeType.PRIMARY, @@ -1372,6 +1372,14 @@ async def liquid_probe( can_bus_only_output = bool( output_option.value & OutputOptions.can_bus_only.value ) + data_files_transposed = ( + None + if data_files is None + else { + sensor_id_for_instrument(probe): data_files[probe] + for probe in data_files.keys() + } + ) positions = await liquid_probe( messenger=self._messenger, tool=tool, @@ -1383,7 +1391,7 @@ async def liquid_probe( csv_output=csv_output, sync_buffer_output=sync_buffer_output, can_bus_only_output=can_bus_only_output, - data_file=data_file, + data_files=data_files_transposed, auto_zero_sensor=auto_zero_sensor, num_baseline_reads=num_baseline_reads, sensor_id=sensor_id_for_instrument(probe), @@ -1533,8 +1541,14 @@ async def update_tip_detector(self, mount: OT3Mount, sensor_count: int) -> None: async def teardown_tip_detector(self, mount: OT3Mount) -> None: await self._tip_presence_manager.clear_detector(mount) - async def get_tip_status(self, mount: OT3Mount) -> TipStateType: - return await self.tip_presence_manager.get_tip_status(mount) + async def get_tip_status( + self, + mount: OT3Mount, + follow_singular_sensor: Optional[InstrumentProbeType] = None, + ) -> TipStateType: + return await self.tip_presence_manager.get_tip_status( + mount, follow_singular_sensor + ) def current_tip_state(self, mount: OT3Mount) -> Optional[bool]: return self.tip_presence_manager.current_tip_state(mount) diff --git a/api/src/opentrons/hardware_control/backends/ot3simulator.py b/api/src/opentrons/hardware_control/backends/ot3simulator.py index 528f8794c0d..f0f774ca186 100644 --- a/api/src/opentrons/hardware_control/backends/ot3simulator.py +++ b/api/src/opentrons/hardware_control/backends/ot3simulator.py @@ -346,7 +346,7 @@ async def liquid_probe( plunger_speed: float, threshold_pascals: float, output_format: OutputOptions = OutputOptions.can_bus_only, - data_file: Optional[str] = None, + data_files: Optional[Dict[InstrumentProbeType, str]] = None, auto_zero_sensor: bool = True, num_baseline_reads: int = 10, probe: InstrumentProbeType = InstrumentProbeType.PRIMARY, @@ -782,7 +782,11 @@ def subsystems(self) -> Dict[SubSystem, SubSystemState]: for axis in self._present_axes } - async def get_tip_status(self, mount: OT3Mount) -> TipStateType: + async def get_tip_status( + self, + mount: OT3Mount, + follow_singular_sensor: Optional[InstrumentProbeType] = None, + ) -> TipStateType: return TipStateType(self._sim_tip_state[mount]) def current_tip_state(self, mount: OT3Mount) -> Optional[bool]: diff --git a/api/src/opentrons/hardware_control/backends/ot3utils.py b/api/src/opentrons/hardware_control/backends/ot3utils.py index d585a48f99d..a9108c2365e 100644 --- a/api/src/opentrons/hardware_control/backends/ot3utils.py +++ b/api/src/opentrons/hardware_control/backends/ot3utils.py @@ -544,6 +544,7 @@ def sensor_node_for_pipette(mount: OT3Mount) -> PipetteProbeTarget: _instr_sensor_id_lookup: Dict[InstrumentProbeType, SensorId] = { InstrumentProbeType.PRIMARY: SensorId.S0, InstrumentProbeType.SECONDARY: SensorId.S1, + InstrumentProbeType.BOTH: SensorId.BOTH, } diff --git a/api/src/opentrons/hardware_control/backends/tip_presence_manager.py b/api/src/opentrons/hardware_control/backends/tip_presence_manager.py index 9d2be3901da..f2401d23f69 100644 --- a/api/src/opentrons/hardware_control/backends/tip_presence_manager.py +++ b/api/src/opentrons/hardware_control/backends/tip_presence_manager.py @@ -3,7 +3,7 @@ from typing import cast, Callable, Optional, List, Set from typing_extensions import TypedDict, Literal -from opentrons.hardware_control.types import TipStateType, OT3Mount +from opentrons.hardware_control.types import TipStateType, OT3Mount, InstrumentProbeType from opentrons_hardware.drivers.can_bus import CanMessenger from opentrons_hardware.firmware_bindings.constants import NodeId @@ -14,8 +14,11 @@ from opentrons_shared_data.errors.exceptions import ( TipDetectorNotFound, UnmatchedTipPresenceStates, + GeneralError, ) +from .ot3utils import sensor_id_for_instrument + log = logging.getLogger(__name__) TipListener = Callable[[OT3Mount, bool], None] @@ -111,7 +114,24 @@ def current_tip_state(self, mount: OT3Mount) -> Optional[bool]: return state @staticmethod - def _get_tip_presence(results: List[tip_types.TipNotification]) -> TipStateType: + def _get_tip_presence( + results: List[tip_types.TipNotification], + follow_singular_sensor: Optional[InstrumentProbeType] = None, + ) -> TipStateType: + """ + We can use follow_singular_sensor used to specify that we only care + about the status of one tip presence sensor on a high throughput + pipette, and the other is allowed to be different. + """ + if follow_singular_sensor: + target_sensor_id = sensor_id_for_instrument(follow_singular_sensor) + for r in results: + if r.sensor == target_sensor_id: + return TipStateType(r.presence) + # raise an error if requested sensor response isn't found + raise GeneralError( + message=f"Requested status for sensor {follow_singular_sensor} not found." + ) # more than one sensor reported, we have to check if their states match if len(set(r.presence for r in results)) > 1: raise UnmatchedTipPresenceStates( @@ -119,9 +139,15 @@ def _get_tip_presence(results: List[tip_types.TipNotification]) -> TipStateType: ) return TipStateType(results[0].presence) - async def get_tip_status(self, mount: OT3Mount) -> TipStateType: + async def get_tip_status( + self, + mount: OT3Mount, + follow_singular_sensor: Optional[InstrumentProbeType] = None, + ) -> TipStateType: detector = self.get_detector(mount) - return self._get_tip_presence(await detector.request_tip_status()) + return self._get_tip_presence( + await detector.request_tip_status(), follow_singular_sensor + ) def get_detector(self, mount: OT3Mount) -> TipDetector: detector = self._detectors[self._get_key(mount)] diff --git a/api/src/opentrons/hardware_control/instruments/ot2/pipette.py b/api/src/opentrons/hardware_control/instruments/ot2/pipette.py index 2d20a4f592a..f8a9d48da60 100644 --- a/api/src/opentrons/hardware_control/instruments/ot2/pipette.py +++ b/api/src/opentrons/hardware_control/instruments/ot2/pipette.py @@ -26,6 +26,11 @@ InvalidLiquidClassName, CommandPreconditionViolated, ) +from opentrons_shared_data.pipette.ul_per_mm import ( + piecewise_volume_conversion, + PIPETTING_FUNCTION_FALLBACK_VERSION, + PIPETTING_FUNCTION_LATEST_VERSION, +) from opentrons.types import Point, Mount @@ -33,11 +38,7 @@ from opentrons.config.types import RobotConfig from opentrons.drivers.types import MoveSplit from ..instrument_abc import AbstractInstrument -from ..instrument_helpers import ( - piecewise_volume_conversion, - PIPETTING_FUNCTION_FALLBACK_VERSION, - PIPETTING_FUNCTION_LATEST_VERSION, -) + from .instrument_calibration import ( PipetteOffsetByPipetteMount, load_pipette_offset, diff --git a/api/src/opentrons/hardware_control/instruments/ot3/gripper.py b/api/src/opentrons/hardware_control/instruments/ot3/gripper.py index 3f120f972a6..ba49ea7d5e7 100644 --- a/api/src/opentrons/hardware_control/instruments/ot3/gripper.py +++ b/api/src/opentrons/hardware_control/instruments/ot3/gripper.py @@ -33,7 +33,7 @@ Geometry, ) -RECONFIG_KEYS = {"quirks"} +RECONFIG_KEYS = {"quirks", "grip_force_profile"} MAX_ACCEPTABLE_JAW_DISPLACEMENT: Final = 20 @@ -52,6 +52,7 @@ def __init__( config: GripperDefinition, gripper_cal_offset: GripperCalibrationOffset, gripper_id: str, + jaw_max_offset: Optional[float] = None, ) -> None: self._config = config self._model = config.model @@ -83,7 +84,7 @@ def __init__( self._log.info( f"loaded: {self._model}, gripper offset: {self._calibration_offset}" ) - self._jaw_max_offset: Optional[float] = None + self._jaw_max_offset = jaw_max_offset @property def grip_force_profile(self) -> GripForceProfile: @@ -325,11 +326,13 @@ def _reload_gripper( changed.add(k) if changed.intersection(RECONFIG_KEYS): # Something has changed that requires reconfig + # we shoud recalibrate the jaw as well return ( Gripper( new_config, cal_offset, attached_instr._gripper_id, + None, ), False, ) diff --git a/api/src/opentrons/hardware_control/instruments/ot3/gripper_handler.py b/api/src/opentrons/hardware_control/instruments/ot3/gripper_handler.py index cf2ba55e23d..e327306c19f 100644 --- a/api/src/opentrons/hardware_control/instruments/ot3/gripper_handler.py +++ b/api/src/opentrons/hardware_control/instruments/ot3/gripper_handler.py @@ -51,6 +51,7 @@ def reset_gripper(self) -> None: og_gripper.config, load_gripper_calibration_offset(og_gripper.gripper_id), og_gripper.gripper_id, + og_gripper._jaw_max_offset, ) self._gripper = new_gripper diff --git a/api/src/opentrons/hardware_control/instruments/ot3/pipette.py b/api/src/opentrons/hardware_control/instruments/ot3/pipette.py index b2dc7f01c02..7d72058d1ce 100644 --- a/api/src/opentrons/hardware_control/instruments/ot3/pipette.py +++ b/api/src/opentrons/hardware_control/instruments/ot3/pipette.py @@ -25,12 +25,12 @@ CommandPreconditionViolated, PythonException, ) -from ..instrument_abc import AbstractInstrument -from ..instrument_helpers import ( +from opentrons_shared_data.pipette.ul_per_mm import ( piecewise_volume_conversion, PIPETTING_FUNCTION_FALLBACK_VERSION, PIPETTING_FUNCTION_LATEST_VERSION, ) +from ..instrument_abc import AbstractInstrument from .instrument_calibration import ( save_pipette_offset_calibration, load_pipette_offset, diff --git a/api/src/opentrons/hardware_control/modules/types.py b/api/src/opentrons/hardware_control/modules/types.py index 1a87d60d35e..eb8054a87ee 100644 --- a/api/src/opentrons/hardware_control/modules/types.py +++ b/api/src/opentrons/hardware_control/modules/types.py @@ -64,6 +64,22 @@ def from_model(cls, model: ModuleModel) -> ModuleType: if isinstance(model, MagneticBlockModel): return cls.MAGNETIC_BLOCK + @classmethod + def to_module_fixture_id(cls, module_type: ModuleType) -> str: + if module_type == ModuleType.THERMOCYCLER: + # Thermocyclers are "loaded" in B1 only + return "thermocyclerModuleV2Front" + if module_type == ModuleType.TEMPERATURE: + return "temperatureModuleV2" + if module_type == ModuleType.HEATER_SHAKER: + return "heaterShakerModuleV1" + if module_type == ModuleType.MAGNETIC_BLOCK: + return "magneticBlockV1" + else: + raise ValueError( + f"Module Type {module_type} does not have a related fixture ID." + ) + class MagneticModuleModel(str, Enum): MAGNETIC_V1: str = "magneticModuleV1" diff --git a/api/src/opentrons/hardware_control/nozzle_manager.py b/api/src/opentrons/hardware_control/nozzle_manager.py index 499ddf4c0f6..a25e5e57319 100644 --- a/api/src/opentrons/hardware_control/nozzle_manager.py +++ b/api/src/opentrons/hardware_control/nozzle_manager.py @@ -12,6 +12,8 @@ ) from opentrons_shared_data.errors import ErrorCodes, GeneralError, PythonException +MAXIMUM_NOZZLE_COUNT = 24 + def _nozzle_names_by_row(rows: List[PipetteRowDefinition]) -> Iterator[str]: for row in rows: @@ -267,6 +269,17 @@ def build( (nozzle, physical_nozzles[nozzle]) for nozzle in chain(*rows.values()) ) + if ( + NozzleConfigurationType.determine_nozzle_configuration( + physical_rows, rows, physical_columns, columns + ) + != NozzleConfigurationType.FULL + ): + if len(rows) * len(columns) > MAXIMUM_NOZZLE_COUNT: + raise IncompatibleNozzleConfiguration( + f"Partial Nozzle Layouts may not be configured to contain more than {MAXIMUM_NOZZLE_COUNT} channels." + ) + return cls( starting_nozzle=starting_nozzle, map_store=map_store, diff --git a/api/src/opentrons/hardware_control/ot3api.py b/api/src/opentrons/hardware_control/ot3api.py index 00a5de0628e..84978e2b14b 100644 --- a/api/src/opentrons/hardware_control/ot3api.py +++ b/api/src/opentrons/hardware_control/ot3api.py @@ -1533,6 +1533,12 @@ async def _home_axis(self, axis: Axis) -> None: await self._set_plunger_current_and_home(axis, motor_ok, encoder_ok) return + # TODO: (ba, 2024-04-19): We need to explictly engage the axis and enable + # the motor when we are attempting to move. This should be already + # happening but something on the firmware is either not enabling the motor or + # disabling the motor. + await self.engage_axes([axis]) + # we can move to safe home distance! if encoder_ok and motor_ok: origin, target_pos = await self._retrieve_home_position(axis) @@ -1649,16 +1655,24 @@ async def retract_axis(self, axis: Axis) -> None: motor_ok = self._backend.check_motor_status([axis]) encoder_ok = self._backend.check_encoder_status([axis]) - if motor_ok and encoder_ok: - # we can move to the home position without checking the limit switch - origin = await self._backend.update_position() - target_pos = {axis: self._backend.home_position()[axis]} - await self._backend.move(origin, target_pos, 400, HWStopCondition.none) - else: - # home the axis - await self._home_axis(axis) - await self._cache_current_position() - await self._cache_encoder_position() + async with self._motion_lock: + if motor_ok and encoder_ok: + # TODO: (ba, 2024-04-19): We need to explictly engage the axis and enable + # the motor when we are attempting to move. This should be already + # happening but something on the firmware is either not enabling the motor or + # disabling the motor. + await self.engage_axes([axis]) + + # we can move to the home position without checking the limit switch + origin = await self._backend.update_position() + target_pos = {axis: self._backend.home_position()[axis]} + await self._backend.move(origin, target_pos, 400, HWStopCondition.none) + else: + # home the axis + await self._home_axis(axis) + + await self._cache_current_position() + await self._cache_encoder_position() # Gantry/frame (i.e. not pipette) config API @property @@ -2058,6 +2072,7 @@ async def _high_throughput_check_tip(self) -> AsyncIterator[None]: async def get_tip_presence_status( self, mount: Union[top_types.Mount, OT3Mount], + follow_singular_sensor: Optional[InstrumentProbeType] = None, ) -> TipStateType: """ Check tip presence status. If a high throughput pipette is present, @@ -2071,14 +2086,19 @@ async def get_tip_presence_status( and self._gantry_load == GantryLoad.HIGH_THROUGHPUT ): await stack.enter_async_context(self._high_throughput_check_tip()) - result = await self._backend.get_tip_status(real_mount) + result = await self._backend.get_tip_status( + real_mount, follow_singular_sensor + ) return result async def verify_tip_presence( - self, mount: Union[top_types.Mount, OT3Mount], expected: TipStateType + self, + mount: Union[top_types.Mount, OT3Mount], + expected: TipStateType, + follow_singular_sensor: Optional[InstrumentProbeType] = None, ) -> None: real_mount = OT3Mount.from_mount(mount) - status = await self.get_tip_presence_status(real_mount) + status = await self.get_tip_presence_status(real_mount, follow_singular_sensor) if status != expected: raise FailedTipStateCheck(expected, status.value) @@ -2087,14 +2107,17 @@ async def _force_pick_up_tip( ) -> None: for press in pipette_spec.tip_action_moves: async with self._backend.motor_current(run_currents=press.currents): - target_down = target_position_from_relative( + target = target_position_from_relative( mount, top_types.Point(z=press.distance), self._current_position ) - await self._move(target_down, speed=press.speed, expect_stalls=True) - if press.distance < 0: - # we expect a stall has happened during a downward movement into the tiprack, so - # we want to update the motor estimation - await self._update_position_estimation([Axis.by_mount(mount)]) + if press.distance < 0: + # we expect a stall has happened during a downward movement into the tiprack, so + # we want to update the motor estimation + await self._move(target, speed=press.speed, expect_stalls=True) + await self._update_position_estimation([Axis.by_mount(mount)]) + else: + # we should not ignore stalls that happen during the retract part of the routine + await self._move(target, speed=press.speed, expect_stalls=False) async def _tip_motor_action( self, mount: OT3Mount, pipette_spec: List[TipActionMoveSpec] @@ -2578,7 +2601,7 @@ async def liquid_probe( (probe_settings.plunger_speed * plunger_direction), probe_settings.sensor_threshold_pascals, probe_settings.output_option, - probe_settings.data_file, + probe_settings.data_files, probe_settings.auto_zero_sensor, probe_settings.num_baseline_reads, probe=probe if probe else InstrumentProbeType.PRIMARY, diff --git a/api/src/opentrons/hardware_control/protocols/flex_instrument_configurer.py b/api/src/opentrons/hardware_control/protocols/flex_instrument_configurer.py index 0606b8847f4..9b156f0dffa 100644 --- a/api/src/opentrons/hardware_control/protocols/flex_instrument_configurer.py +++ b/api/src/opentrons/hardware_control/protocols/flex_instrument_configurer.py @@ -1,5 +1,5 @@ """Flex-specific extensions to instrument configuration.""" -from typing import Union +from typing import Union, Optional from typing_extensions import Protocol from .types import MountArgType @@ -9,6 +9,7 @@ ) from opentrons.hardware_control.types import ( TipStateType, + InstrumentProbeType, ) from opentrons.hardware_control.instruments.ot3.instrument_calibration import ( PipetteOffsetSummary, @@ -42,7 +43,10 @@ async def get_tip_presence_status( ... async def verify_tip_presence( - self, mount: MountArgType, expected: TipStateType + self, + mount: MountArgType, + expected: TipStateType, + follow_singular_sensor: Optional[InstrumentProbeType] = None, ) -> None: """Check tip presence status and raise if it does not match `expected`.""" ... diff --git a/api/src/opentrons/hardware_control/types.py b/api/src/opentrons/hardware_control/types.py index 9a153a447d5..1ea79652f34 100644 --- a/api/src/opentrons/hardware_control/types.py +++ b/api/src/opentrons/hardware_control/types.py @@ -624,6 +624,7 @@ class GripperJawState(enum.Enum): class InstrumentProbeType(enum.Enum): PRIMARY = enum.auto() SECONDARY = enum.auto() + BOTH = enum.auto() class GripperProbe(enum.Enum): diff --git a/api/src/opentrons/protocol_api/_parameter_context.py b/api/src/opentrons/protocol_api/_parameter_context.py index 7773653a9c5..8c9debd882c 100644 --- a/api/src/opentrons/protocol_api/_parameter_context.py +++ b/api/src/opentrons/protocol_api/_parameter_context.py @@ -52,6 +52,7 @@ def add_int( description: A description of the parameter as it will show up on the frontend. unit: An optional unit to be appended to the end of the integer as it shown on the frontend. """ + validation.validate_variable_name_unique(variable_name, set(self._parameters)) parameter = parameter_definition.create_int_parameter( display_name=display_name, variable_name=variable_name, @@ -88,6 +89,7 @@ def add_float( description: A description of the parameter as it will show up on the frontend. unit: An optional unit to be appended to the end of the float as it shown on the frontend. """ + validation.validate_variable_name_unique(variable_name, set(self._parameters)) parameter = parameter_definition.create_float_parameter( display_name=display_name, variable_name=variable_name, @@ -115,6 +117,7 @@ def add_bool( default: The default value the boolean parameter will be set to. This will be used in initial analysis. description: A description of the parameter as it will show up on the frontend. """ + validation.validate_variable_name_unique(variable_name, set(self._parameters)) parameter = parameter_definition.create_bool_parameter( display_name=display_name, variable_name=variable_name, @@ -145,6 +148,7 @@ def add_str( Mutually exclusive with minimum and maximum. description: A description of the parameter as it will show up on the frontend. """ + validation.validate_variable_name_unique(variable_name, set(self._parameters)) parameter = parameter_definition.create_str_parameter( display_name=display_name, variable_name=variable_name, diff --git a/api/src/opentrons/protocol_api/core/engine/__init__.py b/api/src/opentrons/protocol_api/core/engine/__init__.py index ded1ff960e0..69287a4edfa 100644 --- a/api/src/opentrons/protocol_api/core/engine/__init__.py +++ b/api/src/opentrons/protocol_api/core/engine/__init__.py @@ -10,6 +10,7 @@ from .well import WellCore ENGINE_CORE_API_VERSION: Final = APIVersion(2, 14) +SET_OFFSET_RESTORED_API_VERSION: Final = APIVersion(2, 18) __all__ = [ "ENGINE_CORE_API_VERSION", diff --git a/api/src/opentrons/protocol_api/core/engine/labware.py b/api/src/opentrons/protocol_api/core/engine/labware.py index 9b48b309aa2..301d7dcdece 100644 --- a/api/src/opentrons/protocol_api/core/engine/labware.py +++ b/api/src/opentrons/protocol_api/core/engine/labware.py @@ -10,9 +10,14 @@ from opentrons.protocol_engine.errors import LabwareNotOnDeckError, ModuleNotOnDeckError from opentrons.protocol_engine.clients import SyncClient as ProtocolEngineClient +from opentrons.protocol_engine.types import ( + LabwareOffsetCreate, + LabwareOffsetVector, +) from opentrons.types import DeckSlotName, Point from opentrons.hardware_control.nozzle_manager import NozzleMap + from ..labware import AbstractLabware, LabwareLoadParams from .well import WellCore @@ -92,8 +97,28 @@ def get_quirks(self) -> List[str]: return self._definition.parameters.quirks or [] def set_calibration(self, delta: Point) -> None: - raise NotImplementedError( - "Setting a labware's calibration after it's been loaded is not supported." + """Add a labware offset for this labware at its current location. + + This will override any previous labware offsets for this definition URI and location, + even if the other labware offset was for a different specific labware instance. + """ + offset_location = self._engine_client.state.geometry.get_offset_location( + self._labware_id + ) + if not offset_location: + raise LabwareNotOnDeckError( + message=f"Cannot set offset for {self.get_name()} as it is not currently in a deck slot.", + details={"kind": "labware-not-in-slot"}, + ) + + request = LabwareOffsetCreate.construct( + definitionUri=self.get_uri(), + location=offset_location, + vector=LabwareOffsetVector(x=delta.x, y=delta.y, z=delta.z), + ) + self._engine_client.add_labware_offset(request) + self._engine_client.reload_labware( + labware_id=self._labware_id, ) def get_calibrated_offset(self) -> Point: diff --git a/api/src/opentrons/protocol_api/core/engine/protocol.py b/api/src/opentrons/protocol_api/core/engine/protocol.py index e3146a98a08..4089dff4b4d 100644 --- a/api/src/opentrons/protocol_api/core/engine/protocol.py +++ b/api/src/opentrons/protocol_api/core/engine/protocol.py @@ -3,7 +3,7 @@ from typing import Dict, Optional, Type, Union, List, Tuple, TYPE_CHECKING from opentrons.protocol_engine.commands import LoadModuleResult -from opentrons_shared_data.deck.dev_types import DeckDefinitionV4, SlotDefV3 +from opentrons_shared_data.deck.dev_types import DeckDefinitionV5, SlotDefV3 from opentrons_shared_data.labware.labware_definition import LabwareDefinition from opentrons_shared_data.labware.dev_types import LabwareDefinition as LabwareDefDict from opentrons_shared_data.pipette.dev_types import PipetteNameType @@ -409,7 +409,6 @@ def load_module( robot_type = self._engine_client.state.config.robot_type normalized_deck_slot = deck_slot.to_equivalent_for_robot_type(robot_type) - self._ensure_module_location(normalized_deck_slot, module_type) result = self._engine_client.load_module( model=EngineModuleModel(model), @@ -602,7 +601,7 @@ def set_last_location( self._last_location = location self._last_mount = mount - def get_deck_definition(self) -> DeckDefinitionV4: + def get_deck_definition(self) -> DeckDefinitionV5: """Get the geometry definition of the robot's deck.""" return self._engine_client.state.labware.get_deck_definition() @@ -622,14 +621,6 @@ def get_staging_slot_definitions(self) -> Dict[str, SlotDefV3]: self._engine_client.state.addressable_areas.get_staging_slot_definitions() ) - def _ensure_module_location( - self, slot: DeckSlotName, module_type: ModuleType - ) -> None: - slot_def = self.get_slot_definition(slot) - compatible_modules = slot_def["compatibleModuleTypes"] - if module_type.value not in compatible_modules: - raise ValueError(f"A {module_type.value} cannot be loaded into slot {slot}") - def get_slot_item( self, slot_name: Union[DeckSlotName, StagingSlotName] ) -> Union[LabwareCore, ModuleCore, NonConnectedModuleCore, None]: diff --git a/api/src/opentrons/protocol_api/core/legacy/deck.py b/api/src/opentrons/protocol_api/core/legacy/deck.py index 9a9092af5ae..685f0f5d553 100644 --- a/api/src/opentrons/protocol_api/core/legacy/deck.py +++ b/api/src/opentrons/protocol_api/core/legacy/deck.py @@ -280,6 +280,11 @@ def resolve_module_location( compatible_modules = slot_def["compatibleModuleTypes"] if module_type.value in compatible_modules: return location + elif ( + self._definition["robot"]["model"] == "OT-3 Standard" + and ModuleType.to_module_fixture_id(module_type) == slot_def["id"] + ): + return location else: raise ValueError( f"A {dn_from_type[module_type]} cannot be loaded" diff --git a/api/src/opentrons/protocol_api/core/legacy/legacy_protocol_core.py b/api/src/opentrons/protocol_api/core/legacy/legacy_protocol_core.py index d99c3032a71..02fc2003733 100644 --- a/api/src/opentrons/protocol_api/core/legacy/legacy_protocol_core.py +++ b/api/src/opentrons/protocol_api/core/legacy/legacy_protocol_core.py @@ -1,7 +1,7 @@ import logging from typing import Dict, List, Optional, Set, Union, cast, Tuple -from opentrons_shared_data.deck.dev_types import DeckDefinitionV4, SlotDefV3 +from opentrons_shared_data.deck.dev_types import DeckDefinitionV5, SlotDefV3 from opentrons_shared_data.labware.dev_types import LabwareDefinition from opentrons_shared_data.pipette.dev_types import PipetteNameType from opentrons_shared_data.robot.dev_types import RobotType @@ -491,7 +491,7 @@ def get_labware_on_labware( ) -> Optional[LegacyLabwareCore]: assert False, "get_labware_on_labware only supported on engine core" - def get_deck_definition(self) -> DeckDefinitionV4: + def get_deck_definition(self) -> DeckDefinitionV5: """Get the geometry definition of the robot's deck.""" assert False, "get_deck_definition only supported on engine core" diff --git a/api/src/opentrons/protocol_api/core/protocol.py b/api/src/opentrons/protocol_api/core/protocol.py index 8ed83388c07..a554c14e306 100644 --- a/api/src/opentrons/protocol_api/core/protocol.py +++ b/api/src/opentrons/protocol_api/core/protocol.py @@ -5,7 +5,7 @@ from abc import abstractmethod, ABC from typing import Generic, List, Optional, Union, Tuple, Dict, TYPE_CHECKING -from opentrons_shared_data.deck.dev_types import DeckDefinitionV4, SlotDefV3 +from opentrons_shared_data.deck.dev_types import DeckDefinitionV5, SlotDefV3 from opentrons_shared_data.pipette.dev_types import PipetteNameType from opentrons_shared_data.labware.dev_types import LabwareDefinition from opentrons_shared_data.robot.dev_types import RobotType @@ -188,7 +188,7 @@ def set_last_location( ... @abstractmethod - def get_deck_definition(self) -> DeckDefinitionV4: + def get_deck_definition(self) -> DeckDefinitionV5: """Get the geometry definition of the robot's deck.""" @abstractmethod diff --git a/api/src/opentrons/protocol_api/create_protocol_context.py b/api/src/opentrons/protocol_api/create_protocol_context.py index f48510049fa..b01d4bbbbe0 100644 --- a/api/src/opentrons/protocol_api/create_protocol_context.py +++ b/api/src/opentrons/protocol_api/create_protocol_context.py @@ -4,7 +4,6 @@ from opentrons_shared_data.labware.dev_types import LabwareDefinition -from opentrons.config import feature_flags from opentrons.hardware_control import ( HardwareControlAPI, ThreadManager, @@ -123,8 +122,7 @@ def create_protocol_context( sync_hardware=sync_hardware, ) - # TODO(mc, 2022-8-22): remove `disable_fast_protocol_upload` - elif use_simulating_core and not feature_flags.disable_fast_protocol_upload(): + elif use_simulating_core: legacy_deck = LegacyDeck(deck_type=deck_type) core = LegacyProtocolCoreSimulator( sync_hardware=sync_hardware, diff --git a/api/src/opentrons/protocol_api/instrument_context.py b/api/src/opentrons/protocol_api/instrument_context.py index e070b896a6e..68e39888405 100644 --- a/api/src/opentrons/protocol_api/instrument_context.py +++ b/api/src/opentrons/protocol_api/instrument_context.py @@ -60,6 +60,8 @@ """The version after which a partial nozzle configuration became available for the 96 Channel Pipette.""" _PARTIAL_NOZZLE_CONFIGURATION_AUTOMATIC_TIP_TRACKING_IN = APIVersion(2, 18) """The version after which automatic tip tracking supported partially configured nozzle layouts.""" +_DISPOSAL_LOCATION_OFFSET_ADDED_IN = APIVersion(2, 18) +"""The version after which offsets for deck configured trash containers and changes to alternating tip drop behavior were introduced.""" class InstrumentContext(publisher.CommandPublisher): @@ -1086,16 +1088,22 @@ def drop_tip( well = maybe_well elif isinstance(location, (TrashBin, WasteChute)): + # In 2.16 and 2.17, we would always automatically use automatic alternate tip drop locations regardless + # of whether you explicitly passed the disposal location as a location or if none was provided. Now, in + # 2.18 and moving forward, passing it in will bypass the automatic behavior and instead go to the set + # offset or the XY center if none is provided. + if self.api_version < _DISPOSAL_LOCATION_OFFSET_ADDED_IN: + alternate_drop_location = True with publisher.publish_context( broker=self.broker, command=cmds.drop_tip_in_disposal_location( instrument=self, location=location ), ): - # TODO(jbl 2024-02-28) when adding 2.18 api version checks, set alternate_tip_drop - # if below that version for compatability self._core.drop_tip_in_disposal_location( - location, home_after=home_after + location, + home_after=home_after, + alternate_tip_drop=alternate_drop_location, ) self._last_tip_picked_up_from = None return self @@ -1928,13 +1936,6 @@ def configure_nozzle_layout( should be of the same format used when identifying wells by name. Required unless setting ``style=ALL``. - .. note:: - When using the ``COLUMN`` layout, the only fully supported value is - ``start="A12"``. You can use ``start="A1"``, but this will disable tip - tracking and you will have to specify the ``location`` every time you - call :py:meth:`.pick_up_tip`, such that the pipette picks up columns of - tips *from right to left* on the tip rack. - :type start: str or ``None`` :param tip_racks: Behaves the same as setting the ``tip_racks`` parameter of :py:meth:`.load_instrument`. If not specified, the new configuration resets @@ -1947,6 +1948,20 @@ def configure_nozzle_layout( # :param front_right: The nozzle at the front left of the layout. Only used for # NozzleLayout.QUADRANT configurations. # :type front_right: str or ``None`` + # + # NOTE: Disabled layouts error case can be removed once desired map configurations + # have appropriate data regarding tip-type to map current values added to the + # pipette definitions. + disabled_layouts = [ + NozzleLayout.ROW, + NozzleLayout.SINGLE, + NozzleLayout.QUADRANT, + ] + if style in disabled_layouts: + raise ValueError( + f"Nozzle layout configuration of style {style.value} is currently unsupported." + ) + if style != NozzleLayout.ALL: if start is None: raise ValueError( diff --git a/api/src/opentrons/protocol_api/labware.py b/api/src/opentrons/protocol_api/labware.py index ecb4d06ac5b..3b7ae943208 100644 --- a/api/src/opentrons/protocol_api/labware.py +++ b/api/src/opentrons/protocol_api/labware.py @@ -35,7 +35,7 @@ from ._liquid import Liquid from ._types import OffDeckType from .core import well_grid -from .core.engine import ENGINE_CORE_API_VERSION +from .core.engine import ENGINE_CORE_API_VERSION, SET_OFFSET_RESTORED_API_VERSION from .core.labware import AbstractLabware from .core.module import AbstractModuleCore from .core.core_map import LoadedCoreMap @@ -594,16 +594,13 @@ def set_offset(self, x: float, y: float, z: float) -> None: Instead, use Labware Position Check in the app or on the touchscreen. """ - if self._api_version >= ENGINE_CORE_API_VERSION: - # TODO(mm, 2023-02-13): See Jira RCORE-535. - # - # Until that issue is resolved, the only way to simulate or run a - # >=ENGINE_CORE_API_VERSION protocol is through the Opentrons App. - # Therefore, in >=ENGINE_CORE_API_VERSION protocols, - # there's no legitimate way to use this method. + if ( + self._api_version >= ENGINE_CORE_API_VERSION + and self._api_version < SET_OFFSET_RESTORED_API_VERSION + ): raise APIVersionError( - "Labware.set_offset() is not supported when apiLevel is 2.14 or higher." - " Use a lower apiLevel" + "Labware.set_offset() is not supported when apiLevel is 2.14, 2.15, 2.16, or 2.17." + " Use apilevel 2.13 or below, or 2.18 or above to set offset," " or use the Opentrons App's Labware Position Check." ) else: diff --git a/api/src/opentrons/protocol_api/module_contexts.py b/api/src/opentrons/protocol_api/module_contexts.py index 5e9d412835e..654a6ec46c1 100644 --- a/api/src/opentrons/protocol_api/module_contexts.py +++ b/api/src/opentrons/protocol_api/module_contexts.py @@ -151,7 +151,7 @@ def load_labware( load_location = loaded_adapter._core else: load_location = self._core - + name = validation.ensure_lowercase_name(name) labware_core = self._protocol_core.load_labware( load_name=name, label=label, @@ -467,9 +467,9 @@ def engage( if height is not None: if self._api_version >= _MAGNETIC_MODULE_HEIGHT_PARAM_REMOVED_IN: raise APIVersionError( - "The height parameter of MagneticModuleContext.engage() was removed" - " in {_MAGNETIC_MODULE_HEIGHT_PARAM_REMOVED_IN}." - " Use offset or height_from_base instead." + f"The height parameter of MagneticModuleContext.engage() was removed" + f" in {_MAGNETIC_MODULE_HEIGHT_PARAM_REMOVED_IN}." + f" Use offset or height_from_base instead." ) self._core.engage(height_from_home=height) diff --git a/api/src/opentrons/protocol_api/validation.py b/api/src/opentrons/protocol_api/validation.py index f714f35cecd..eb72c6b6dfd 100644 --- a/api/src/opentrons/protocol_api/validation.py +++ b/api/src/opentrons/protocol_api/validation.py @@ -87,6 +87,10 @@ class InvalidTrashBinLocationError(ValueError): """An error raised when attempting to load trash bins in invalid slots.""" +class InvalidFixtureLocationError(ValueError): + """An error raised when attempting to load a fixture in an invalid cutout.""" + + def ensure_mount_for_pipette( mount: Union[str, Mount, None], pipette: PipetteNameType ) -> Mount: diff --git a/api/src/opentrons/protocol_engine/actions/actions.py b/api/src/opentrons/protocol_engine/actions/actions.py index ee36e76f7de..adcf4f9e40b 100644 --- a/api/src/opentrons/protocol_engine/actions/actions.py +++ b/api/src/opentrons/protocol_engine/actions/actions.py @@ -55,10 +55,7 @@ class PauseAction: @dataclass(frozen=True) class StopAction: - """Stop the current engine execution. - - After a StopAction, the engine status will be marked as stopped. - """ + """Request engine execution to stop soon.""" from_estop: bool = False @@ -119,6 +116,7 @@ class QueueCommandAction: created_at: datetime request: CommandCreate request_hash: Optional[str] + failed_command_id: Optional[str] = None @dataclass(frozen=True) diff --git a/api/src/opentrons/protocol_engine/clients/sync_client.py b/api/src/opentrons/protocol_engine/clients/sync_client.py index f95611c1b4c..ed6a499090b 100644 --- a/api/src/opentrons/protocol_engine/clients/sync_client.py +++ b/api/src/opentrons/protocol_engine/clients/sync_client.py @@ -27,6 +27,7 @@ Liquid, NozzleLayoutConfigurationType, AddressableOffsetVector, + LabwareOffsetCreate, ) from .transports import ChildThreadTransport @@ -92,6 +93,10 @@ def reset_tips(self, labware_id: str) -> None: labware_id=labware_id, ) + def add_labware_offset(self, request: LabwareOffsetCreate) -> None: + """Add a labware offset.""" + self._transport.call_method("add_labware_offset", request=request) + def set_pipette_movement_speed( self, pipette_id: str, speed: Optional[float] ) -> None: @@ -127,6 +132,19 @@ def load_labware( return cast(commands.LoadLabwareResult, result) + def reload_labware( + self, + labware_id: str, + ) -> commands.ReloadLabwareResult: + """Execute a ReloadLabware command and return the result.""" + request = commands.ReloadLabwareCreate( + params=commands.ReloadLabwareParams( + labwareId=labware_id, + ) + ) + result = self._transport.execute_command(request=request) + return cast(commands.ReloadLabwareResult, result) + # TODO (spp, 2022-12-14): https://opentrons.atlassian.net/browse/RLAB-237 def move_labware( self, diff --git a/api/src/opentrons/protocol_engine/commands/__init__.py b/api/src/opentrons/protocol_engine/commands/__init__.py index 3dfe6eaf51f..123425e464f 100644 --- a/api/src/opentrons/protocol_engine/commands/__init__.py +++ b/api/src/opentrons/protocol_engine/commands/__init__.py @@ -19,7 +19,7 @@ from . import thermocycler from . import calibration -from .hash_command_params import hash_command_params +from .hash_command_params import hash_protocol_command_params from .generate_command_schema import generate_command_schema from .command import ( @@ -120,6 +120,14 @@ LoadLabwareCommandType, ) +from .reload_labware import ( + ReloadLabware, + ReloadLabwareParams, + ReloadLabwareCreate, + ReloadLabwareResult, + ReloadLabwareCommandType, +) + from .load_liquid import ( LoadLiquid, LoadLiquidParams, @@ -333,7 +341,7 @@ "CommandStatus", "CommandIntent", # command parameter hashing - "hash_command_params", + "hash_protocol_command_params", # command schema generation "generate_command_schema", # aspirate command models @@ -402,6 +410,12 @@ "LoadLabwareParams", "LoadLabwareResult", "LoadLabwareCommandType", + # reload labware command models + "ReloadLabware", + "ReloadLabwareCreate", + "ReloadLabwareParams", + "ReloadLabwareResult", + "ReloadLabwareCommandType", # load module command models "LoadModule", "LoadModuleCreate", diff --git a/api/src/opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py b/api/src/opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py index 67d60eead86..8ce067963ab 100644 --- a/api/src/opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +++ b/api/src/opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py @@ -80,46 +80,25 @@ async def execute( ot3_api = ensure_ot3_hardware( self._hardware_api, ) - # the 96-channel mount is disengaged during gripper calibration and - # must be homed before the gantry position can be called + max_height_z_tip = ot3_api.get_instrument_max_height(Mount.LEFT) + # disengage the gripper z mount if present and enabled await ot3_api.prepare_for_mount_movement(Mount.LEFT) - current_position_mount = await ot3_api.gantry_position( + + await ot3_api.retract(Mount.LEFT) + current_pos = await ot3_api.gantry_position( Mount.LEFT, critical_point=CriticalPoint.MOUNT ) - max_height_z_mount = ot3_api.get_instrument_max_height( - Mount.LEFT, critical_point=CriticalPoint.MOUNT + await ot3_api.move_to( + mount=Mount.LEFT, + abs_position=Point(x=_ATTACH_POINT.x, y=_ATTACH_POINT.y, z=current_pos.z), + critical_point=CriticalPoint.MOUNT, ) - max_height_z_tip = ot3_api.get_instrument_max_height(Mount.LEFT) - # avoid using motion planning waypoints because we do not need to move the z at this moment - movement_points = [ - # move the z to the highest position - Point( - x=current_position_mount.x, - y=current_position_mount.y, - z=max_height_z_mount, - ), - # move in x,y without going down the z - Point(x=_ATTACH_POINT.x, y=_ATTACH_POINT.y, z=max_height_z_mount), - ] - - await ot3_api.prepare_for_mount_movement(Mount.LEFT) - for movement in movement_points: - await ot3_api.move_to( - mount=Mount.LEFT, - abs_position=movement, - critical_point=CriticalPoint.MOUNT, - ) if params.mount != MountType.EXTENSION: - - # disengage the gripper z to enable the e-brake, this prevents the gripper - # z from dropping when the right mount carriage gets released from the - # mount during 96-channel detach flow - if ot3_api.has_gripper(): - await ot3_api.disengage_axes([Axis.Z_G]) - if params.maintenancePosition == MaintenancePosition.ATTACH_INSTRUMENT: - mount_to_axis = Axis.by_mount(params.mount.to_hw_mount()) + mount = params.mount.to_hw_mount() + mount_to_axis = Axis.by_mount(mount) + await ot3_api.prepare_for_mount_movement(mount) await ot3_api.move_axes( { mount_to_axis: _INSTRUMENT_ATTACH_Z_POINT, @@ -134,6 +113,7 @@ async def execute( Axis.Z_R: max_motion_range + _RIGHT_MOUNT_Z_MARGIN, } ) + await ot3_api.disengage_axes([Axis.Z_L, Axis.Z_R]) return MoveToMaintenancePositionResult() diff --git a/api/src/opentrons/protocol_engine/commands/command.py b/api/src/opentrons/protocol_engine/commands/command.py index 5c2ab46b06f..fcdd7387355 100644 --- a/api/src/opentrons/protocol_engine/commands/command.py +++ b/api/src/opentrons/protocol_engine/commands/command.py @@ -13,6 +13,8 @@ TypeVar, Tuple, List, + Type, + Union, ) from pydantic import BaseModel, Field @@ -29,11 +31,11 @@ from ..state import StateView -CommandParamsT = TypeVar("CommandParamsT", bound=BaseModel) - -CommandResultT = TypeVar("CommandResultT", bound=BaseModel) - -CommandPrivateResultT = TypeVar("CommandPrivateResultT") +_ParamsT = TypeVar("_ParamsT", bound=BaseModel) +_ParamsT_contra = TypeVar("_ParamsT_contra", bound=BaseModel, contravariant=True) +_ResultT = TypeVar("_ResultT", bound=BaseModel) +_ResultT_co = TypeVar("_ResultT_co", bound=BaseModel, covariant=True) +_PrivateResultT_co = TypeVar("_PrivateResultT_co", covariant=True) class CommandStatus(str, Enum): @@ -55,9 +57,10 @@ class CommandIntent(str, Enum): PROTOCOL = "protocol" SETUP = "setup" + FIXIT = "fixit" -class BaseCommandCreate(GenericModel, Generic[CommandParamsT]): +class BaseCommandCreate(GenericModel, Generic[_ParamsT]): """Base class for command creation requests. You shouldn't use this class directly; instead, use or define @@ -71,7 +74,7 @@ class BaseCommandCreate(GenericModel, Generic[CommandParamsT]): "execution behavior" ), ) - params: CommandParamsT = Field(..., description="Command execution data payload") + params: _ParamsT = Field(..., description="Command execution data payload") intent: Optional[CommandIntent] = Field( None, description=( @@ -96,7 +99,7 @@ class BaseCommandCreate(GenericModel, Generic[CommandParamsT]): ) -class BaseCommand(GenericModel, Generic[CommandParamsT, CommandResultT]): +class BaseCommand(GenericModel, Generic[_ParamsT, _ResultT]): """Base command model. You shouldn't use this class directly; instead, use or define @@ -126,8 +129,8 @@ class BaseCommand(GenericModel, Generic[CommandParamsT, CommandResultT]): ), ) status: CommandStatus = Field(..., description="Command execution status") - params: CommandParamsT = Field(..., description="Command execution data payload") - result: Optional[CommandResultT] = Field( + params: _ParamsT = Field(..., description="Command execution data payload") + result: Optional[_ResultT] = Field( None, description="Command execution result data, if succeeded", ) @@ -159,11 +162,22 @@ class BaseCommand(GenericModel, Generic[CommandParamsT, CommandResultT]): " the command's execution or the command's generation." ), ) + failedCommandId: Optional[str] = Field( + None, + description=( + "FIXIT command use only. Reference of the failed command id we are trying to fix." + ), + ) + + _ImplementationCls: Union[ + Type[AbstractCommandImpl[_ParamsT, _ResultT]], + Type[AbstractCommandWithPrivateResultImpl[_ParamsT, _ResultT, object]], + ] class AbstractCommandImpl( ABC, - Generic[CommandParamsT, CommandResultT], + Generic[_ParamsT_contra, _ResultT_co], ): """Abstract command creation and execution implementation. @@ -197,14 +211,14 @@ def __init__( pass @abstractmethod - async def execute(self, params: CommandParamsT) -> CommandResultT: + async def execute(self, params: _ParamsT_contra) -> _ResultT_co: """Execute the command, mapping data from execution into a response model.""" ... class AbstractCommandWithPrivateResultImpl( ABC, - Generic[CommandParamsT, CommandResultT, CommandPrivateResultT], + Generic[_ParamsT_contra, _ResultT_co, _PrivateResultT_co], ): """Abstract command creation and execution implementation if the command has private results. @@ -240,7 +254,7 @@ def __init__( @abstractmethod async def execute( - self, params: CommandParamsT - ) -> Tuple[CommandResultT, CommandPrivateResultT]: + self, params: _ParamsT_contra + ) -> Tuple[_ResultT_co, _PrivateResultT_co]: """Execute the command, mapping data from execution into a response model.""" ... diff --git a/api/src/opentrons/protocol_engine/commands/command_unions.py b/api/src/opentrons/protocol_engine/commands/command_unions.py index dc4cc18c35a..7674508cc96 100644 --- a/api/src/opentrons/protocol_engine/commands/command_unions.py +++ b/api/src/opentrons/protocol_engine/commands/command_unions.py @@ -100,6 +100,14 @@ LoadLabwareCommandType, ) +from .reload_labware import ( + ReloadLabware, + ReloadLabwareParams, + ReloadLabwareCreate, + ReloadLabwareResult, + ReloadLabwareCommandType, +) + from .load_liquid import ( LoadLiquid, LoadLiquidParams, @@ -304,6 +312,7 @@ Home, RetractAxis, LoadLabware, + ReloadLabware, LoadLiquid, LoadModule, LoadPipette, @@ -368,6 +377,7 @@ HomeParams, RetractAxisParams, LoadLabwareParams, + ReloadLabwareParams, LoadLiquidParams, LoadModuleParams, LoadPipetteParams, @@ -431,6 +441,7 @@ HomeCommandType, RetractAxisCommandType, LoadLabwareCommandType, + ReloadLabwareCommandType, LoadLiquidCommandType, LoadModuleCommandType, LoadPipetteCommandType, @@ -494,6 +505,7 @@ HomeCreate, RetractAxisCreate, LoadLabwareCreate, + ReloadLabwareCreate, LoadLiquidCreate, LoadModuleCreate, LoadPipetteCreate, @@ -558,6 +570,7 @@ HomeResult, RetractAxisResult, LoadLabwareResult, + ReloadLabwareResult, LoadLiquidResult, LoadModuleResult, LoadPipetteResult, diff --git a/api/src/opentrons/protocol_engine/commands/configuring_common.py b/api/src/opentrons/protocol_engine/commands/configuring_common.py index 17ffc2adef4..6998bcbac7b 100644 --- a/api/src/opentrons/protocol_engine/commands/configuring_common.py +++ b/api/src/opentrons/protocol_engine/commands/configuring_common.py @@ -1,6 +1,5 @@ """Common configuration command base models.""" -from pydantic import BaseModel, Field from dataclasses import dataclass from opentrons.hardware_control.nozzle_manager import ( NozzleMap, @@ -10,18 +9,18 @@ @dataclass class PipetteConfigUpdateResultMixin: - """A mixin-suitable model for adding pipette config to results.""" + """A mixin-suitable model for adding pipette config to private results.""" pipette_id: str serial_number: str config: pipette_data_provider.LoadedStaticPipetteData -class PipetteNozzleLayoutResultMixin(BaseModel): +@dataclass +class PipetteNozzleLayoutResultMixin: """A nozzle layout result for updating the pipette state.""" pipette_id: str - nozzle_map: NozzleMap = Field( - ..., - description="A dataclass object holding information about the current nozzle configuration.", - ) + + nozzle_map: NozzleMap + """A dataclass object holding information about the current nozzle configuration.""" diff --git a/api/src/opentrons/protocol_engine/commands/hash_command_params.py b/api/src/opentrons/protocol_engine/commands/hash_command_params.py index 39a042e55dd..1d124101d4c 100644 --- a/api/src/opentrons/protocol_engine/commands/hash_command_params.py +++ b/api/src/opentrons/protocol_engine/commands/hash_command_params.py @@ -9,7 +9,7 @@ # TODO(mm, 2023-04-28): # This implementation will not notice that commands are different if they have different params # but share the same commandType. We should also hash command params. (Jira RCORE-326.) -def hash_command_params( +def hash_protocol_command_params( create: CommandCreate, last_hash: Optional[str] ) -> Optional[str]: """Given a command create object, return a hash. @@ -28,12 +28,11 @@ def hash_command_params( The command hash, if the command is a protocol command. `None` if the command is a setup command. """ - if create.intent == CommandIntent.SETUP: + if create.intent in [CommandIntent.SETUP, CommandIntent.FIXIT]: return None - else: - # We avoid Python's built-in hash() function because it's not stable across - # runs of the Python interpreter. (Jira RSS-215.) - last_contribution = b"" if last_hash is None else last_hash.encode("ascii") - this_contribution = md5(create.commandType.encode("ascii")).digest() - to_hash = last_contribution + this_contribution - return md5(to_hash).hexdigest() + # We avoid Python's built-in hash() function because it's not stable across + # runs of the Python interpreter. (Jira RSS-215.) + last_contribution = b"" if last_hash is None else last_hash.encode("ascii") + this_contribution = md5(create.commandType.encode("ascii")).digest() + to_hash = last_contribution + this_contribution + return md5(to_hash).hexdigest() diff --git a/api/src/opentrons/protocol_engine/commands/load_module.py b/api/src/opentrons/protocol_engine/commands/load_module.py index 1d877d08941..5c1d474be4d 100644 --- a/api/src/opentrons/protocol_engine/commands/load_module.py +++ b/api/src/opentrons/protocol_engine/commands/load_module.py @@ -5,7 +5,15 @@ from pydantic import BaseModel, Field from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate -from ..types import DeckSlotLocation, ModuleModel, ModuleDefinition +from ..types import ( + DeckSlotLocation, + ModuleType, + ModuleModel, + ModuleDefinition, +) +from opentrons.types import DeckSlotName + +from opentrons.protocol_engine.resources import deck_configuration_provider if TYPE_CHECKING: from ..state import StateView @@ -104,9 +112,22 @@ def __init__( async def execute(self, params: LoadModuleParams) -> LoadModuleResult: """Check that the requested module is attached and assign its identifier.""" - self._state_view.addressable_areas.raise_if_area_not_in_deck_configuration( - params.location.slotName.id - ) + module_type = params.model.as_type() + self._ensure_module_location(params.location.slotName, module_type) + + if self._state_view.config.robot_type == "OT-2 Standard": + self._state_view.addressable_areas.raise_if_area_not_in_deck_configuration( + params.location.slotName.id + ) + else: + addressable_area = self._state_view.geometry._modules.ensure_and_convert_module_fixture_location( + deck_slot=params.location.slotName, + deck_type=self._state_view.config.deck_type, + model=params.model, + ) + self._state_view.addressable_areas.raise_if_area_not_in_deck_configuration( + addressable_area + ) verified_location = self._state_view.geometry.ensure_location_not_occupied( params.location @@ -132,6 +153,30 @@ async def execute(self, params: LoadModuleParams) -> LoadModuleResult: definition=loaded_module.definition, ) + def _ensure_module_location( + self, slot: DeckSlotName, module_type: ModuleType + ) -> None: + if self._state_view.config.robot_type == "OT-2 Standard": + slot_def = self._state_view.addressable_areas.get_slot_definition(slot.id) + compatible_modules = slot_def["compatibleModuleTypes"] + if module_type.value not in compatible_modules: + raise ValueError( + f"A {module_type.value} cannot be loaded into slot {slot}" + ) + else: + cutout_fixture_id = ModuleType.to_module_fixture_id(module_type) + module_fixture = deck_configuration_provider.get_cutout_fixture( + cutout_fixture_id, + self._state_view.addressable_areas.state.deck_definition, + ) + cutout_id = ( + self._state_view.addressable_areas.get_cutout_id_by_deck_slot_name(slot) + ) + if cutout_id not in module_fixture["mayMountTo"]: + raise ValueError( + f"A {module_type.value} cannot be loaded into slot {slot}" + ) + class LoadModule(BaseCommand[LoadModuleParams, LoadModuleResult]): """The model for a load module command.""" diff --git a/api/src/opentrons/protocol_engine/commands/reload_labware.py b/api/src/opentrons/protocol_engine/commands/reload_labware.py new file mode 100644 index 00000000000..247f717feb9 --- /dev/null +++ b/api/src/opentrons/protocol_engine/commands/reload_labware.py @@ -0,0 +1,86 @@ +"""Reload labware command request, result, and implementation models.""" +from __future__ import annotations +from pydantic import BaseModel, Field +from typing import TYPE_CHECKING, Optional, Type +from typing_extensions import Literal + +from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate + +if TYPE_CHECKING: + from ..state import StateView + from ..execution import EquipmentHandler + + +ReloadLabwareCommandType = Literal["reloadLabware"] + + +class ReloadLabwareParams(BaseModel): + """Payload required to load a labware into a slot.""" + + labwareId: str = Field( + ..., description="The already-loaded labware instance to update." + ) + + +class ReloadLabwareResult(BaseModel): + """Result data from the execution of a LoadLabware command.""" + + labwareId: str = Field( + ..., + description="An ID to reference this labware in subsequent commands. Same as the one in the parameters.", + ) + offsetId: Optional[str] = Field( + # Default `None` instead of `...` so this field shows up as non-required in + # OpenAPI. The server is allowed to omit it or make it null. + None, + description=( + "An ID referencing the labware offset that will apply" + " to the reloaded labware." + " This offset will be in effect until the labware is moved" + " with a `moveLabware` command." + " Null or undefined means no offset applies," + " so the default of (0, 0, 0) will be used." + ), + ) + + +class ReloadLabwareImplementation( + AbstractCommandImpl[ReloadLabwareParams, ReloadLabwareResult] +): + """Reload labware command implementation.""" + + def __init__( + self, equipment: EquipmentHandler, state_view: StateView, **kwargs: object + ) -> None: + self._equipment = equipment + self._state_view = state_view + + async def execute(self, params: ReloadLabwareParams) -> ReloadLabwareResult: + """Reload the definition and calibration data for a specific labware.""" + reloaded_labware = await self._equipment.reload_labware( + labware_id=params.labwareId, + ) + + return ReloadLabwareResult( + labwareId=params.labwareId, + offsetId=reloaded_labware.offsetId, + ) + + +class ReloadLabware(BaseCommand[ReloadLabwareParams, ReloadLabwareResult]): + """Reload labware command resource model.""" + + commandType: ReloadLabwareCommandType = "reloadLabware" + params: ReloadLabwareParams + result: Optional[ReloadLabwareResult] + + _ImplementationCls: Type[ReloadLabwareImplementation] = ReloadLabwareImplementation + + +class ReloadLabwareCreate(BaseCommandCreate[ReloadLabwareParams]): + """Reload labware command creation request.""" + + commandType: ReloadLabwareCommandType = "reloadLabware" + params: ReloadLabwareParams + + _CommandCls: Type[ReloadLabware] = ReloadLabware diff --git a/api/src/opentrons/protocol_engine/commands/verify_tip_presence.py b/api/src/opentrons/protocol_engine/commands/verify_tip_presence.py index 1d56c8e66bf..67aa5d1dc34 100644 --- a/api/src/opentrons/protocol_engine/commands/verify_tip_presence.py +++ b/api/src/opentrons/protocol_engine/commands/verify_tip_presence.py @@ -8,7 +8,7 @@ from .pipetting_common import PipetteIdMixin from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate -from ..types import TipPresenceStatus +from ..types import TipPresenceStatus, InstrumentSensorId if TYPE_CHECKING: from ..execution import TipHandler @@ -23,6 +23,9 @@ class VerifyTipPresenceParams(PipetteIdMixin): expectedState: TipPresenceStatus = Field( ..., description="The expected tip presence status on the pipette." ) + followSingularSensor: Optional[InstrumentSensorId] = Field( + default=None, description="The sensor id to follow if the other can be ignored." + ) class VerifyTipPresenceResult(BaseModel): @@ -47,10 +50,16 @@ async def execute(self, params: VerifyTipPresenceParams) -> VerifyTipPresenceRes """Verify if tip presence is as expected for the requested pipette.""" pipette_id = params.pipetteId expected_state = params.expectedState + follow_singular_sensor = ( + InstrumentSensorId.to_instrument_probe_type(params.followSingularSensor) + if params.followSingularSensor + else None + ) await self._tip_handler.verify_tip_presence( pipette_id=pipette_id, expected=expected_state, + follow_singular_sensor=follow_singular_sensor, ) return VerifyTipPresenceResult() diff --git a/api/src/opentrons/protocol_engine/errors/__init__.py b/api/src/opentrons/protocol_engine/errors/__init__.py index d3c3bb6d79e..994e4cc9ed3 100644 --- a/api/src/opentrons/protocol_engine/errors/__init__.py +++ b/api/src/opentrons/protocol_engine/errors/__init__.py @@ -39,6 +39,7 @@ MustHomeError, RunStoppedError, SetupCommandNotAllowedError, + FixitCommandNotAllowedError, ModuleNotAttachedError, ModuleAlreadyPresentError, WrongModuleTypeError, @@ -55,6 +56,7 @@ InvalidHoldTimeError, CannotPerformModuleAction, PauseNotAllowedError, + ResumeFromRecoveryNotAllowedError, GripperNotAttachedError, CannotPerformGripperAction, HardwareNotSupportedError, @@ -65,6 +67,7 @@ LocationIsStagingSlotError, InvalidAxisForRobotType, NotSupportedOnRobotType, + CommandNotAllowedError, ) from .error_occurrence import ErrorOccurrence, ProtocolCommandFailedError @@ -109,6 +112,7 @@ "MustHomeError", "RunStoppedError", "SetupCommandNotAllowedError", + "FixitCommandNotAllowedError", "ModuleNotAttachedError", "ModuleAlreadyPresentError", "WrongModuleTypeError", @@ -124,6 +128,7 @@ "InvalidBlockVolumeError", "InvalidHoldTimeError", "CannotPerformModuleAction", + "ResumeFromRecoveryNotAllowedError", "PauseNotAllowedError", "ProtocolCommandFailedError", "GripperNotAttachedError", @@ -138,5 +143,5 @@ "NotSupportedOnRobotType", # error occurrence models "ErrorOccurrence", - "FailedGripperPickupError", + "CommandNotAllowedError", ] diff --git a/api/src/opentrons/protocol_engine/errors/exceptions.py b/api/src/opentrons/protocol_engine/errors/exceptions.py index 9d9ff99b33e..7f022652d71 100644 --- a/api/src/opentrons/protocol_engine/errors/exceptions.py +++ b/api/src/opentrons/protocol_engine/errors/exceptions.py @@ -505,6 +505,32 @@ def __init__( super().__init__(ErrorCodes.POSITION_UNKNOWN, message, details, wrapping) +class CommandNotAllowedError(ProtocolEngineError): + """Raised when adding a command with bad data.""" + + def __init__( + self, + message: Optional[str] = None, + details: Optional[Dict[str, Any]] = None, + wrapping: Optional[Sequence[EnumeratedError]] = None, + ) -> None: + """Build a CommandNotAllowedError.""" + super().__init__(ErrorCodes.GENERAL_ERROR, message, details, wrapping) + + +class FixitCommandNotAllowedError(ProtocolEngineError): + """Raised when adding a fixit command to a non-recoverable engine.""" + + def __init__( + self, + message: Optional[str] = None, + details: Optional[Dict[str, Any]] = None, + wrapping: Optional[Sequence[EnumeratedError]] = None, + ) -> None: + """Build a SetupCommandNotAllowedError.""" + super().__init__(ErrorCodes.GENERAL_ERROR, message, details, wrapping) + + class SetupCommandNotAllowedError(ProtocolEngineError): """Raised when adding a setup command to a non-idle/non-paused engine.""" @@ -518,6 +544,19 @@ def __init__( super().__init__(ErrorCodes.GENERAL_ERROR, message, details, wrapping) +class ResumeFromRecoveryNotAllowedError(ProtocolEngineError): + """Raised when attempting to resume a run from recovery that has a fixit command in the queue.""" + + def __init__( + self, + message: Optional[str] = None, + details: Optional[Dict[str, Any]] = None, + wrapping: Optional[Sequence[EnumeratedError]] = None, + ) -> None: + """Build a ResumeFromRecoveryNotAllowedError.""" + super().__init__(ErrorCodes.GENERAL_ERROR, message, details, wrapping) + + class PauseNotAllowedError(ProtocolEngineError): """Raised when attempting to pause a run that is not running.""" @@ -951,16 +990,18 @@ def __init__( class EStopActivatedError(ProtocolEngineError): - """Raised when an operation's required pipette tip is not attached.""" + """Represents an E-stop event.""" def __init__( self, - message: Optional[str] = None, - details: Optional[Dict[str, Any]] = None, wrapping: Optional[Sequence[EnumeratedError]] = None, ) -> None: """Build an EStopActivatedError.""" - super().__init__(ErrorCodes.E_STOP_ACTIVATED, message, details, wrapping) + super().__init__( + code=ErrorCodes.E_STOP_ACTIVATED, + message="E-stop activated.", + wrapping=wrapping, + ) class NotSupportedOnRobotType(ProtocolEngineError): diff --git a/api/src/opentrons/protocol_engine/execution/__init__.py b/api/src/opentrons/protocol_engine/execution/__init__.py index 5d2da5e6840..80f2dfd0d99 100644 --- a/api/src/opentrons/protocol_engine/execution/__init__.py +++ b/api/src/opentrons/protocol_engine/execution/__init__.py @@ -8,6 +8,7 @@ LoadedPipetteData, LoadedModuleData, LoadedConfigureForVolumeData, + ReloadedLabwareData, ) from .movement import MovementHandler from .gantry_mover import GantryMover @@ -29,6 +30,7 @@ "create_queue_worker", "EquipmentHandler", "LoadedLabwareData", + "ReloadedLabwareData", "LoadedPipetteData", "LoadedModuleData", "LoadedConfigureForVolumeData", diff --git a/api/src/opentrons/protocol_engine/execution/command_executor.py b/api/src/opentrons/protocol_engine/execution/command_executor.py index 9488d1719e9..d00b5c0a96d 100644 --- a/api/src/opentrons/protocol_engine/execution/command_executor.py +++ b/api/src/opentrons/protocol_engine/execution/command_executor.py @@ -159,7 +159,7 @@ async def execute(self, command_id: str) -> None: if isinstance(error, asyncio.CancelledError): error = RunStoppedError("Run was cancelled") elif isinstance(error, EStopActivatedError): - error = PE_EStopActivatedError(message=str(error), wrapping=[error]) + error = PE_EStopActivatedError(wrapping=[error]) elif not isinstance(error, EnumeratedError): error = PythonException(error) diff --git a/api/src/opentrons/protocol_engine/execution/create_queue_worker.py b/api/src/opentrons/protocol_engine/execution/create_queue_worker.py index 3323aab0aa3..8b59eda5ef2 100644 --- a/api/src/opentrons/protocol_engine/execution/create_queue_worker.py +++ b/api/src/opentrons/protocol_engine/execution/create_queue_worker.py @@ -39,7 +39,6 @@ def create_queue_worker( equipment_handler = EquipmentHandler( hardware_api=hardware_api, state_store=state_store, - action_dispatcher=action_dispatcher, ) movement_handler = MovementHandler( diff --git a/api/src/opentrons/protocol_engine/execution/equipment.py b/api/src/opentrons/protocol_engine/execution/equipment.py index 2487ad50aaa..7dc2f3bcfaa 100644 --- a/api/src/opentrons/protocol_engine/execution/equipment.py +++ b/api/src/opentrons/protocol_engine/execution/equipment.py @@ -1,6 +1,6 @@ """Equipment command side-effect logic.""" from dataclasses import dataclass -from typing import Optional, overload +from typing import Optional, overload, Union from opentrons_shared_data.pipette.dev_types import PipetteNameType @@ -22,7 +22,6 @@ TemperatureModuleId, ThermocyclerModuleId, ) -from ..actions import ActionDispatcher from ..errors import ( FailedToLoadPipetteError, LabwareDefinitionDoesNotExistError, @@ -44,6 +43,7 @@ LabwareOffsetLocation, ModuleModel, ModuleDefinition, + AddressableAreaLocation, ) @@ -56,6 +56,14 @@ class LoadedLabwareData: offsetId: Optional[str] +@dataclass(frozen=True) +class ReloadedLabwareData: + """The result of a reload labware procedure.""" + + location: LabwareLocation + offsetId: Optional[str] + + @dataclass(frozen=True) class LoadedPipetteData: """The result of a load pipette procedure.""" @@ -98,7 +106,6 @@ def __init__( self, hardware_api: HardwareControlAPI, state_store: StateStore, - action_dispatcher: ActionDispatcher, labware_data_provider: Optional[LabwareDataProvider] = None, module_data_provider: Optional[ModuleDataProvider] = None, model_utils: Optional[ModelUtils] = None, @@ -109,7 +116,6 @@ def __init__( """Initialize an EquipmentHandler instance.""" self._hardware_api = hardware_api self._state_store = state_store - self._action_dispatcher = action_dispatcher self._labware_data_provider = labware_data_provider or LabwareDataProvider() self._module_data_provider = module_data_provider or ModuleDataProvider() self._model_utils = model_utils or ModelUtils() @@ -173,6 +179,25 @@ async def load_labware( labware_id=labware_id, definition=definition, offsetId=offset_id ) + async def reload_labware(self, labware_id: str) -> ReloadedLabwareData: + """Reload an already-loaded labware. This cannot change the labware location. + + Args: + labware_id: The ID of the already-loaded labware. + + Raises: + LabwareNotLoadedError: If `labware_id` does not reference a loaded labware. + + """ + location = self._state_store.labware.get_location(labware_id) + definition_uri = self._state_store.labware.get_definition_uri(labware_id) + offset_id = self.find_applicable_labware_offset_id( + labware_definition_uri=definition_uri, + labware_location=location, + ) + + return ReloadedLabwareData(location=location, offsetId=offset_id) + async def load_pipette( self, pipette_name: PipetteNameType, @@ -252,7 +277,7 @@ async def load_pipette( async def load_magnetic_block( self, model: ModuleModel, - location: DeckSlotLocation, + location: Union[DeckSlotLocation, AddressableAreaLocation], module_id: Optional[str], ) -> LoadedModuleData: """Ensure the required magnetic block is attached. @@ -317,10 +342,14 @@ async def load_module( for hw_mod in self._hardware_api.attached_modules ] + serial_number_at_locaiton = self._state_store.geometry._addressable_areas.get_fixture_serial_from_deck_configuration_by_deck_slot( + location.slotName + ) attached_module = self._state_store.modules.select_hardware_module_to_load( model=model, location=location, attached_modules=attached_modules, + expected_serial_number=serial_number_at_locaiton, ) else: diff --git a/api/src/opentrons/protocol_engine/execution/tip_handler.py b/api/src/opentrons/protocol_engine/execution/tip_handler.py index 51cf4708377..e43685d2ebb 100644 --- a/api/src/opentrons/protocol_engine/execution/tip_handler.py +++ b/api/src/opentrons/protocol_engine/execution/tip_handler.py @@ -3,7 +3,7 @@ from typing_extensions import Protocol as TypingProtocol from opentrons.hardware_control import HardwareControlAPI -from opentrons.hardware_control.types import FailedTipStateCheck +from opentrons.hardware_control.types import FailedTipStateCheck, InstrumentProbeType from opentrons_shared_data.errors.exceptions import ( CommandPreconditionViolated, CommandParameterLimitViolated, @@ -74,7 +74,10 @@ async def get_tip_presence(self, pipette_id: str) -> TipPresenceStatus: """Get tip presence status on the pipette.""" async def verify_tip_presence( - self, pipette_id: str, expected: TipPresenceStatus + self, + pipette_id: str, + expected: TipPresenceStatus, + follow_singular_sensor: Optional[InstrumentProbeType] = None, ) -> None: """Verify the expected tip presence status.""" @@ -237,7 +240,10 @@ async def get_tip_presence(self, pipette_id: str) -> TipPresenceStatus: return TipPresenceStatus.UNKNOWN async def verify_tip_presence( - self, pipette_id: str, expected: TipPresenceStatus + self, + pipette_id: str, + expected: TipPresenceStatus, + follow_singular_sensor: Optional[InstrumentProbeType] = None, ) -> None: """Verify the expecterd tip presence status of the pipette. @@ -247,7 +253,9 @@ async def verify_tip_presence( try: ot3api = ensure_ot3_hardware(hardware_api=self._hardware_api) hw_mount = self._state_view.pipettes.get_mount(pipette_id).to_hw_mount() - await ot3api.verify_tip_presence(hw_mount, expected.to_hw_state()) + await ot3api.verify_tip_presence( + hw_mount, expected.to_hw_state(), follow_singular_sensor + ) except HardwareNotSupportedError: # Tip presence sensing is not supported on the OT2 pass @@ -332,7 +340,10 @@ async def add_tip(self, pipette_id: str, tip: TipGeometry) -> None: assert False, "TipHandler.add_tip should not be used with virtual pipettes" async def verify_tip_presence( - self, pipette_id: str, expected: TipPresenceStatus + self, + pipette_id: str, + expected: TipPresenceStatus, + follow_singular_sensor: Optional[InstrumentProbeType] = None, ) -> None: """Verify tip presence. diff --git a/api/src/opentrons/protocol_engine/protocol_engine.py b/api/src/opentrons/protocol_engine/protocol_engine.py index bd995f4339a..0c4f2c4b670 100644 --- a/api/src/opentrons/protocol_engine/protocol_engine.py +++ b/api/src/opentrons/protocol_engine/protocol_engine.py @@ -5,7 +5,6 @@ from opentrons.protocol_engine.actions.actions import ResumeFromRecoveryAction from opentrons.protocol_engine.error_recovery_policy import ( ErrorRecoveryPolicy, - ErrorRecoveryType, error_recovery_by_ff, ) @@ -18,7 +17,7 @@ EnumeratedError, ) -from .errors import ProtocolCommandFailedError, ErrorOccurrence +from .errors import ProtocolCommandFailedError, ErrorOccurrence, CommandNotAllowedError from .errors.exceptions import EStopActivatedError from . import commands, slot_standardization from .resources import ModelUtils, ModuleDataProvider @@ -58,7 +57,6 @@ HardwareStoppedAction, ResetTipsAction, SetPipetteMovementSpeedAction, - FailCommandAction, ) @@ -159,8 +157,12 @@ def play(self, deck_configuration: Optional[DeckConfigurationType] = None) -> No else: self._hardware_api.resume(HardwarePauseType.PAUSE) - def pause(self) -> None: - """Pause executing commands in the queue.""" + def request_pause(self) -> None: + """Make command execution pause soon. + + This will try to pause in the middle of the ongoing command, if there is one. + Otherwise, whenever the next command begins, the pause will happen then. + """ action = self._state_store.commands.validate_action_allowed( PauseAction(source=PauseSource.CLIENT) ) @@ -174,7 +176,9 @@ def resume_from_recovery(self) -> None: ) self._action_dispatcher.dispatch(action) - def add_command(self, request: commands.CommandCreate) -> commands.Command: + def add_command( + self, request: commands.CommandCreate, failed_command_id: Optional[str] = None + ) -> commands.Command: """Add a command to the `ProtocolEngine`'s queue. Arguments: @@ -189,16 +193,29 @@ def add_command(self, request: commands.CommandCreate) -> commands.Command: but the engine was not idle or paused. RunStoppedError: the run has been stopped, so no new commands may be added. + CommandNotAllowedError: the request specified a failed command id + with a non fixit command. """ request = slot_standardization.standardize_command( request, self.state_view.config.robot_type ) + if failed_command_id and request.intent != commands.CommandIntent.FIXIT: + raise CommandNotAllowedError( + "failed command id should be supplied with a FIXIT command." + ) + command_id = self._model_utils.generate_id() - request_hash = commands.hash_command_params( - create=request, - last_hash=self._state_store.commands.get_latest_command_hash(), - ) + if request.intent in ( + commands.CommandIntent.SETUP, + commands.CommandIntent.FIXIT, + ): + request_hash = None + else: + request_hash = commands.hash_protocol_command_params( + create=request, + last_hash=self._state_store.commands.get_latest_protocol_command_hash(), + ) action = self.state_view.commands.validate_action_allowed( QueueCommandAction( @@ -206,6 +223,7 @@ def add_command(self, request: commands.CommandCreate) -> commands.Command: request_hash=request_hash, command_id=command_id, created_at=self._model_utils.get_timestamp(), + failed_command_id=failed_command_id, ) ) self._action_dispatcher.dispatch(action) @@ -273,14 +291,8 @@ async def add_and_execute_command_wait_for_recovery( ) return completed_command - def estop( - self, - # TODO(mm, 2024-03-26): Maintenance runs are a robot-server concept that - # ProtocolEngine should not have to know about. Can this be simplified or - # defined in other terms? - maintenance_run: bool, - ) -> None: - """Signal to the engine that an estop event occurred. + def estop(self) -> None: + """Signal to the engine that an E-stop event occurred. If an estop happens while the robot is moving, lower layers physically stop motion and raise the event as an exception, which fails the Protocol Engine @@ -288,95 +300,48 @@ def estop( However, if an estop happens in between commands, or in the middle of a command like `comment` or `waitForDuration` that doesn't access the hardware, - `ProtocolEngine` needs to be told about it so it can treat it as a fatal run - error and stop executing more commands. This method is how to do that. - - If there are any queued commands for the engine, they will be marked - as failed due to the estop event. If there aren't any queued commands - *and* this is a maintenance run (which has commands queued one-by-one), - a series of actions will mark the engine as Stopped. In either case the - queue worker will be deactivated; the primary difference is that the former - case will expect the protocol runner to `finish()` the engine, whereas the - maintenance run will be put into a state wherein the engine can be discarded. - """ - if self._state_store.commands.get_is_stopped(): - return - running_or_next_queued_id = ( - self._state_store.commands.get_running_command_id() - or self._state_store.commands.get_queue_ids().head(None) - # TODO(mm, 2024-04-02): This logic looks wrong whenever the next queued - # command is a setup command, which is the normal case in maintenance - # runs. Setup commands won't show up in commands.get_queue_ids(). - ) - running_or_next_queued = ( - self._state_store.commands.get(running_or_next_queued_id) - if running_or_next_queued_id is not None - else None - ) - - if running_or_next_queued_id is not None: - assert running_or_next_queued is not None + `ProtocolEngine` needs to be told about it so it can interrupt the command + and stop executing any more. This method is how to do that. - fail_action = FailCommandAction( - command_id=running_or_next_queued_id, - # FIXME(mm, 2024-04-02): As of https://github.com/Opentrons/opentrons/pull/14726, - # this action is only legal if the command is running, not queued. - running_command=running_or_next_queued, - error_id=self._model_utils.generate_id(), - failed_at=self._model_utils.get_timestamp(), - error=EStopActivatedError(message="Estop Activated"), - notes=[], - type=ErrorRecoveryType.FAIL_RUN, - ) - self._action_dispatcher.dispatch(fail_action) - - # The FailCommandAction above will have cleared all the queued protocol - # OR setup commands, depending on whether we gave it a protocol or setup - # command. We want both to be cleared in either case. So, do that here. - running_or_next_queued_id = self._state_store.commands.get_queue_ids().head( - None - ) - if running_or_next_queued_id is not None: - running_or_next_queued = self._state_store.commands.get( - running_or_next_queued_id - ) - fail_action = FailCommandAction( - command_id=running_or_next_queued_id, - # FIXME(mm, 2024-04-02): As of https://github.com/Opentrons/opentrons/pull/14726, - # this action is only legal if the command is running, not queued. - running_command=running_or_next_queued, - error_id=self._model_utils.generate_id(), - failed_at=self._model_utils.get_timestamp(), - error=EStopActivatedError(message="Estop Activated"), - notes=[], - type=ErrorRecoveryType.FAIL_RUN, - ) - self._action_dispatcher.dispatch(fail_action) - self._queue_worker.cancel() - elif maintenance_run: - stop_action = self._state_store.commands.validate_action_allowed( + This acts roughly like `request_stop()`. After calling this, you should call + `finish()` with an EStopActivatedError. + """ + try: + action = self._state_store.commands.validate_action_allowed( StopAction(from_estop=True) ) - self._action_dispatcher.dispatch(stop_action) - hardware_stop_action = HardwareStoppedAction( - completed_at=self._model_utils.get_timestamp(), - finish_error_details=FinishErrorDetails( - error=EStopActivatedError(message="Estop Activated"), - error_id=self._model_utils.generate_id(), - created_at=self._model_utils.get_timestamp(), - ), + except Exception: # todo(mm, 2024-04-16): Catch a more specific type. + # This is likely called from some hardware API callback that doesn't care + # about ProtocolEngine lifecycle or what methods are valid to call at what + # times. So it makes more sense for us to no-op here than to propagate this + # as an error. + _log.info( + "ProtocolEngine cannot handle E-stop event right now. Ignoring it.", + exc_info=True, ) - self._action_dispatcher.dispatch(hardware_stop_action) - self._queue_worker.cancel() - else: - _log.info("estop pressed before protocol was started, taking no action.") + return + self._action_dispatcher.dispatch(action) + # self._queue_worker.cancel() will try to interrupt any ongoing command. + # Unfortunately, if it's a hardware command, this interruption will race + # against the E-stop exception propagating up from lower layers. But we need to + # do this because we want to make sure non-hardware commands, like + # `waitForDuration`, are also interrupted. + self._queue_worker.cancel() + # Unlike self.request_stop(), we don't need to do + # self._hardware_api.cancel_execution_and_running_tasks(). Since this was an + # E-stop event, the hardware API already knows. - async def stop(self) -> None: - """Stop execution immediately, halting all motion and cancelling future commands. + async def request_stop(self) -> None: + """Make command execution stop soon. - After an engine has been `stop`'ed, it cannot be restarted. + This will try to interrupt the ongoing command, if there is one. Future commands + are canceled. However, by the time this method returns, things may not have + settled by the time this method returns; the last command may still be + running. - After a `stop`, you must still call `finish` to give the engine a chance + After a stop has been requested, the engine cannot be restarted. + + After a stop request, you must still call `finish` to give the engine a chance to clean up resources and propagate errors. """ action = self._state_store.commands.validate_action_allowed(StopAction()) @@ -409,14 +374,20 @@ async def finish( set_run_status: bool = True, post_run_hardware_state: PostRunHardwareState = PostRunHardwareState.HOME_AND_STAY_ENGAGED, ) -> None: - """Gracefully finish using the ProtocolEngine, waiting for it to become idle. + """Finish using the `ProtocolEngine`. + + This does a few things: + + 1. It may do post-run actions like homing and dropping tips. This depends on the + arguments passed as well as heuristics based on the history of the engine. + 2. It waits for the engine to be done controlling the robot's hardware. + 3. It releases internal resources, like background tasks. - The engine will finish executing its current command (if any), - and then shut down. After an engine has been `finished`'ed, it cannot - be restarted. + It's safe to call `finish()` multiple times. After you call `finish()`, + the engine can't be restarted. This method should not raise. If any exceptions happened during execution that were not - properly caught by the CommandExecutor, or if any exceptions happen during this + properly caught by `ProtocolEngine` internals, or if any exceptions happen during this `finish()` call, they should be saved as `.state_view.get_summary().errors`. Arguments: @@ -430,12 +401,11 @@ async def finish( if self._state_store.commands.state.stopped_by_estop: # This handles the case where the E-stop was pressed while we were *not* in the middle # of some hardware interaction that would raise it as an exception. For example, imagine - # we were paused between two commands, or imagine we were executing a very long run of - # comment commands. + # we were paused between two commands, or imagine we were executing a waitForDuration. drop_tips_after_run = False post_run_hardware_state = PostRunHardwareState.DISENGAGE_IN_PLACE if error is None: - error = EStopActivatedError(message="Estop was activated during a run") + error = EStopActivatedError() if error: # If the run had an error, check if that error indicates an E-stop. diff --git a/api/src/opentrons/protocol_engine/resources/deck_configuration_provider.py b/api/src/opentrons/protocol_engine/resources/deck_configuration_provider.py index 112be3663cd..648bd4f4484 100644 --- a/api/src/opentrons/protocol_engine/resources/deck_configuration_provider.py +++ b/api/src/opentrons/protocol_engine/resources/deck_configuration_provider.py @@ -1,7 +1,7 @@ """Deck configuration resource provider.""" from typing import List, Set, Tuple -from opentrons_shared_data.deck.dev_types import DeckDefinitionV4, CutoutFixture +from opentrons_shared_data.deck.dev_types import DeckDefinitionV5, CutoutFixture from opentrons.types import DeckSlotName @@ -17,11 +17,10 @@ CutoutDoesNotExistError, FixtureDoesNotExistError, AddressableAreaDoesNotExistError, - FixtureDoesNotProvideAreasError, ) -def get_cutout_position(cutout_id: str, deck_definition: DeckDefinitionV4) -> DeckPoint: +def get_cutout_position(cutout_id: str, deck_definition: DeckDefinitionV5) -> DeckPoint: """Get the base position of a cutout on the deck.""" for cutout in deck_definition["locations"]["cutouts"]: if cutout_id == cutout["id"]: @@ -32,7 +31,7 @@ def get_cutout_position(cutout_id: str, deck_definition: DeckDefinitionV4) -> De def get_cutout_fixture( - cutout_fixture_id: str, deck_definition: DeckDefinitionV4 + cutout_fixture_id: str, deck_definition: DeckDefinitionV5 ) -> CutoutFixture: """Gets cutout fixture from deck that matches the cutout fixture ID provided.""" for cutout_fixture in deck_definition["cutoutFixtures"]: @@ -44,20 +43,18 @@ def get_cutout_fixture( def get_provided_addressable_area_names( - cutout_fixture_id: str, cutout_id: str, deck_definition: DeckDefinitionV4 + cutout_fixture_id: str, cutout_id: str, deck_definition: DeckDefinitionV5 ) -> List[str]: """Gets a list of the addressable areas provided by the cutout fixture on the cutout.""" cutout_fixture = get_cutout_fixture(cutout_fixture_id, deck_definition) try: return cutout_fixture["providesAddressableAreas"][cutout_id] - except KeyError as exception: - raise FixtureDoesNotProvideAreasError( - f"Cutout fixture {cutout_fixture['id']} does not provide addressable areas for {cutout_id}" - ) from exception + except KeyError: + return [] def get_addressable_area_display_name( - addressable_area_name: str, deck_definition: DeckDefinitionV4 + addressable_area_name: str, deck_definition: DeckDefinitionV5 ) -> str: """Get the display name for an addressable area name.""" for addressable_area in deck_definition["locations"]["addressableAreas"]: @@ -69,7 +66,7 @@ def get_addressable_area_display_name( def get_potential_cutout_fixtures( - addressable_area_name: str, deck_definition: DeckDefinitionV4 + addressable_area_name: str, deck_definition: DeckDefinitionV5 ) -> Tuple[str, Set[PotentialCutoutFixture]]: """Given an addressable area name, gets the cutout ID associated with it and a set of potential fixtures.""" potential_fixtures = [] @@ -102,7 +99,7 @@ def get_addressable_area_from_name( addressable_area_name: str, cutout_position: DeckPoint, base_slot: DeckSlotName, - deck_definition: DeckDefinitionV4, + deck_definition: DeckDefinitionV5, ) -> AddressableArea: """Given a name and a cutout position, get an addressable area on the deck.""" for addressable_area in deck_definition["locations"]["addressableAreas"]: diff --git a/api/src/opentrons/protocol_engine/resources/deck_data_provider.py b/api/src/opentrons/protocol_engine/resources/deck_data_provider.py index 6098c2f4301..017fc58f552 100644 --- a/api/src/opentrons/protocol_engine/resources/deck_data_provider.py +++ b/api/src/opentrons/protocol_engine/resources/deck_data_provider.py @@ -9,7 +9,7 @@ load as load_deck, DEFAULT_DECK_DEFINITION_VERSION, ) -from opentrons_shared_data.deck.dev_types import DeckDefinitionV4 +from opentrons_shared_data.deck.dev_types import DeckDefinitionV5 from opentrons.protocols.models import LabwareDefinition from opentrons.types import DeckSlotName @@ -39,10 +39,10 @@ def __init__( self._deck_type = deck_type self._labware_data = labware_data or LabwareDataProvider() - async def get_deck_definition(self) -> DeckDefinitionV4: + async def get_deck_definition(self) -> DeckDefinitionV5: """Get a labware definition given the labware's identification.""" - def sync() -> DeckDefinitionV4: + def sync() -> DeckDefinitionV5: return load_deck( name=self._deck_type.value, version=DEFAULT_DECK_DEFINITION_VERSION ) @@ -51,7 +51,7 @@ def sync() -> DeckDefinitionV4: async def get_deck_fixed_labware( self, - deck_definition: DeckDefinitionV4, + deck_definition: DeckDefinitionV5, ) -> List[DeckFixedLabware]: """Get a list of all labware fixtures from a given deck definition.""" labware: List[DeckFixedLabware] = [] diff --git a/api/src/opentrons/protocol_engine/state/addressable_areas.py b/api/src/opentrons/protocol_engine/state/addressable_areas.py index 04894fe3338..909beffbe86 100644 --- a/api/src/opentrons/protocol_engine/state/addressable_areas.py +++ b/api/src/opentrons/protocol_engine/state/addressable_areas.py @@ -4,7 +4,7 @@ from opentrons_shared_data.robot.dev_types import RobotType from opentrons_shared_data.deck.dev_types import ( - DeckDefinitionV4, + DeckDefinitionV5, SlotDefV3, CutoutFixture, ) @@ -56,7 +56,7 @@ class AddressableAreaState: potential_cutout_fixtures_by_cutout_id: Dict[str, Set[PotentialCutoutFixture]] - deck_definition: DeckDefinitionV4 + deck_definition: DeckDefinitionV5 deck_configuration: Optional[DeckConfigurationType] """The host robot's full deck configuration. @@ -94,7 +94,7 @@ class AddressableAreaState: def _get_conflicting_addressable_areas_error_string( potential_cutout_fixtures: Set[PotentialCutoutFixture], loaded_addressable_areas: Dict[str, AddressableArea], - deck_definition: DeckDefinitionV4, + deck_definition: DeckDefinitionV5, ) -> str: loaded_areas_on_cutout = set() for fixture in potential_cutout_fixtures: @@ -158,7 +158,7 @@ def __init__( self, deck_configuration: DeckConfigurationType, config: Config, - deck_definition: DeckDefinitionV4, + deck_definition: DeckDefinitionV5, ) -> None: """Initialize an addressable area store and its state.""" if config.use_simulated_deck_config: @@ -224,11 +224,11 @@ def _handle_command(self, command: Command) -> None: @staticmethod def _get_addressable_areas_from_deck_configuration( - deck_config: DeckConfigurationType, deck_definition: DeckDefinitionV4 + deck_config: DeckConfigurationType, deck_definition: DeckDefinitionV5 ) -> Dict[str, AddressableArea]: """Return all addressable areas provided by the given deck configuration.""" addressable_areas = [] - for cutout_id, cutout_fixture_id in deck_config: + for cutout_id, cutout_fixture_id, opentrons_module_serial_number in deck_config: provided_addressable_areas = ( deck_configuration_provider.get_provided_addressable_area_names( cutout_fixture_id, cutout_id, deck_definition @@ -351,7 +351,7 @@ def get_all_cutout_fixtures(self) -> Optional[List[str]]: assert self._state.deck_configuration is not None return [ cutout_fixture_id - for _, cutout_fixture_id in self._state.deck_configuration + for _, cutout_fixture_id, _serial in self._state.deck_configuration ] def _get_loaded_addressable_area( @@ -453,11 +453,31 @@ def get_addressable_area_position( """ addressable_area = self._get_addressable_area_from_deck_data( addressable_area_name=addressable_area_name, - do_compatibility_check=do_compatibility_check, + do_compatibility_check=False, # This should probably not default to false ) position = addressable_area.position return Point(x=position.x, y=position.y, z=position.z) + def get_addressable_area_offsets_from_cutout( + self, + addressable_area_name: str, + ) -> Point: + """Get the offset form cutout fixture of an addressable area.""" + for addressable_area in self.state.deck_definition["locations"][ + "addressableAreas" + ]: + if addressable_area["id"] == addressable_area_name: + area_offset = addressable_area["offsetFromCutoutFixture"] + position = Point( + x=area_offset[0], + y=area_offset[1], + z=area_offset[2], + ) + return Point(x=position.x, y=position.y, z=position.z) + raise ValueError( + f"No matching addressable area named {addressable_area_name} identified." + ) + def get_addressable_area_bounding_box( self, addressable_area_name: str, @@ -499,6 +519,10 @@ def get_addressable_area_center(self, addressable_area_name: str) -> Point: z=position.z, ) + def get_cutout_id_by_deck_slot_name(self, slot_name: DeckSlotName) -> str: + """Get the Cutout ID of a given Deck Slot by Deck Slot Name.""" + return DECK_SLOT_TO_CUTOUT_MAP[slot_name] + def get_fixture_by_deck_slot_name( self, slot_name: DeckSlotName ) -> Optional[CutoutFixture]: @@ -508,7 +532,11 @@ def get_fixture_by_deck_slot_name( slot_cutout_id = DECK_SLOT_TO_CUTOUT_MAP[slot_name] slot_cutout_fixture = None # This will only ever be one under current assumptions - for cutout_id, cutout_fixture_id in deck_config: + for ( + cutout_id, + cutout_fixture_id, + opentrons_module_serial_number, + ) in deck_config: if cutout_id == slot_cutout_id: slot_cutout_fixture = ( deck_configuration_provider.get_cutout_fixture( @@ -532,6 +560,23 @@ def get_fixture_height(self, cutout_fixture_name: str) -> float: ) return cutout_fixture["height"] + def get_fixture_serial_from_deck_configuration_by_deck_slot( + self, slot_name: DeckSlotName + ) -> Optional[str]: + """Get the serial number provided by the deck configuration for a Fixture at a given location.""" + deck_config = self.state.deck_configuration + if deck_config: + slot_cutout_id = DECK_SLOT_TO_CUTOUT_MAP[slot_name] + # This will only ever be one under current assumptions + for ( + cutout_id, + cutout_fixture_id, + opentrons_module_serial_number, + ) in deck_config: + if cutout_id == slot_cutout_id: + return opentrons_module_serial_number + return None + def get_slot_definition(self, slot_id: str) -> SlotDefV3: """Get the definition of a slot in the deck. diff --git a/api/src/opentrons/protocol_engine/state/change_notifier.py b/api/src/opentrons/protocol_engine/state/change_notifier.py deleted file mode 100644 index 3c72f277913..00000000000 --- a/api/src/opentrons/protocol_engine/state/change_notifier.py +++ /dev/null @@ -1,19 +0,0 @@ -"""Simple state change notification interface.""" -import asyncio - - -class ChangeNotifier: - """An interface tto emit or subscribe to state change notifications.""" - - def __init__(self) -> None: - """Initialize the ChangeNotifier with an internal Event.""" - self._event = asyncio.Event() - - def notify(self) -> None: - """Notify all `wait`'ers that the state has changed.""" - self._event.set() - - async def wait(self) -> None: - """Wait until the next state change notification.""" - self._event.clear() - await self._event.wait() diff --git a/api/src/opentrons/protocol_engine/state/command_history.py b/api/src/opentrons/protocol_engine/state/command_history.py index 6a66a2b8209..b21fca030ae 100644 --- a/api/src/opentrons/protocol_engine/state/command_history.py +++ b/api/src/opentrons/protocol_engine/state/command_history.py @@ -33,6 +33,9 @@ class CommandHistory: _queued_setup_command_ids: OrderedSet[str] """The IDs of queued setup commands, in FIFO order""" + _queued_fixit_command_ids: OrderedSet[str] + """The IDs of queued fixit commands, in FIFO order""" + _running_command_id: Optional[str] """The ID of the currently running command, if any""" @@ -43,6 +46,7 @@ def __init__(self) -> None: self._all_command_ids = [] self._queued_command_ids = OrderedSet() self._queued_setup_command_ids = OrderedSet() + self._queued_fixit_command_ids = OrderedSet() self._commands_by_id = OrderedDict() self._running_command_id = None self._terminal_command_id = None @@ -135,6 +139,10 @@ def get_setup_queue_ids(self) -> OrderedSet[str]: """Get the IDs of all queued setup commands, in FIFO order.""" return self._queued_setup_command_ids + def get_fixit_queue_ids(self) -> OrderedSet[str]: + """Get the IDs of all queued fixit commands, in FIFO order.""" + return self._queued_fixit_command_ids + def clear_queue(self) -> None: """Clears all commands within the queued command ids structure.""" self._queued_command_ids.clear() @@ -143,6 +151,10 @@ def clear_setup_queue(self) -> None: """Clears all commands within the queued setup command ids structure.""" self._queued_setup_command_ids.clear() + def clear_fixit_queue(self) -> None: + """Clears all commands within the queued setup command ids structure.""" + self._queued_fixit_command_ids.clear() + def set_command_queued(self, command: Command) -> None: """Validate and mark a command as queued in the command history.""" assert command.status == CommandStatus.QUEUED @@ -157,6 +169,8 @@ def set_command_queued(self, command: Command) -> None: if command.intent == CommandIntent.SETUP: self._add_to_setup_queue(command.id) + elif command.intent == CommandIntent.FIXIT: + self._add_to_fixit_queue(command.id) else: self._add_to_queue(command.id) @@ -177,6 +191,7 @@ def set_command_running(self, command: Command) -> None: self._remove_queue_id(command.id) self._remove_setup_queue_id(command.id) + self._remove_fixit_queue_id(command.id) def set_command_succeeded(self, command: Command) -> None: """Validate and mark a command as succeeded in the command history.""" @@ -239,6 +254,10 @@ def _add_to_setup_queue(self, command_id: str) -> None: """Add a new ID to the queued setup.""" self._queued_setup_command_ids.add(command_id) + def _add_to_fixit_queue(self, command_id: str) -> None: + """Add a new ID to the queued fixit.""" + self._queued_fixit_command_ids.add(command_id) + def _remove_queue_id(self, command_id: str) -> None: """Remove a specific command from the queued command ids structure.""" self._queued_command_ids.discard(command_id) @@ -247,6 +266,10 @@ def _remove_setup_queue_id(self, command_id: str) -> None: """Remove a specific command from the queued setup command ids structure.""" self._queued_setup_command_ids.discard(command_id) + def _remove_fixit_queue_id(self, command_id: str) -> None: + """Remove a specific command from the queued fixit command ids structure.""" + self._queued_fixit_command_ids.discard(command_id) + def _set_terminal_command_id(self, command_id: str) -> None: """Set the ID of the most recently dequeued command.""" self._terminal_command_id = command_id diff --git a/api/src/opentrons/protocol_engine/state/commands.py b/api/src/opentrons/protocol_engine/state/commands.py index 1ae0cb1ed68..7500b16d631 100644 --- a/api/src/opentrons/protocol_engine/state/commands.py +++ b/api/src/opentrons/protocol_engine/state/commands.py @@ -38,6 +38,8 @@ ErrorOccurrence, RobotDoorOpenError, SetupCommandNotAllowedError, + FixitCommandNotAllowedError, + ResumeFromRecoveryNotAllowedError, PauseNotAllowedError, UnexpectedProtocolError, ProtocolCommandFailedError, @@ -184,8 +186,8 @@ class CommandState: finish_error: Optional[ErrorOccurrence] """The error that happened during the post-run finish steps (homing & dropping tips), if any.""" - latest_command_hash: Optional[str] - """The latest hash value received in a QueueCommandAction. + latest_protocol_command_hash: Optional[str] + """The latest PROTOCOL command hash value received in a QueueCommandAction. This value can be used to generate future hashes. """ @@ -219,7 +221,7 @@ def __init__( recovery_target_command_id=None, run_completed_at=None, run_started_at=None, - latest_command_hash=None, + latest_protocol_command_hash=None, stopped_by_estop=False, ) @@ -241,12 +243,13 @@ def handle_action(self, action: Action) -> None: # noqa: C901 params=action.request.params, # type: ignore[arg-type] intent=action.request.intent, status=CommandStatus.QUEUED, + failedCommandId=action.failed_command_id, ) self._state.command_history.set_command_queued(queued_command) if action.request_hash is not None: - self._state.latest_command_hash = action.request_hash + self._state.latest_protocol_command_hash = action.request_hash elif isinstance(action, RunCommandAction): prev_entry = self._state.command_history.get(action.command_id) @@ -321,6 +324,20 @@ def handle_action(self, action: Action) -> None: # noqa: C901 self._state.command_history.clear_queue() else: assert_never(action.type) + elif prev_entry.command.intent == CommandIntent.FIXIT: + other_command_ids_to_fail = ( + self._state.command_history.get_fixit_queue_ids() + ) + for command_id in other_command_ids_to_fail: + # TODO(mc, 2022-06-06): add new "cancelled" status or similar + self._update_to_failed( + command_id=command_id, + failed_at=action.failed_at, + error_occurrence=None, + error_recovery_type=None, + notes=None, + ) + self._state.command_history.clear_fixit_queue() else: assert_never(prev_entry.command.intent) @@ -339,15 +356,21 @@ def handle_action(self, action: Action) -> None: # noqa: C901 self._state.queue_status = QueueStatus.PAUSED elif isinstance(action, ResumeFromRecoveryAction): + self._state.command_history.clear_fixit_queue() self._state.queue_status = QueueStatus.RUNNING self._state.recovery_target_command_id = None elif isinstance(action, StopAction): if not self._state.run_result: + if self._state.queue_status == QueueStatus.AWAITING_RECOVERY: + self._state.recovery_target_command_id = None + self._state.queue_status = QueueStatus.PAUSED - self._state.run_result = RunResult.STOPPED if action.from_estop: self._state.stopped_by_estop = True + self._state.run_result = RunResult.FAILED + else: + self._state.run_result = RunResult.STOPPED elif isinstance(action, FinishAction): if not self._state.run_result: @@ -361,12 +384,12 @@ def handle_action(self, action: Action) -> None: # noqa: C901 else: self._state.run_result = RunResult.STOPPED - if action.error_details: - self._state.run_error = self._map_run_exception_to_error_occurrence( - action.error_details.error_id, - action.error_details.created_at, - action.error_details.error, - ) + if not self._state.run_error and action.error_details: + self._state.run_error = self._map_run_exception_to_error_occurrence( + action.error_details.error_id, + action.error_details.created_at, + action.error_details.error, + ) elif isinstance(action, HardwareStoppedAction): self._state.queue_status = QueueStatus.PAUSED @@ -604,9 +627,18 @@ def get_next_to_execute(self) -> Optional[str]: if self._state.run_result: raise RunStoppedError("Engine was stopped") + # if queue is in recovery mode, return the next fixit command + next_fixit_cmd = self._state.command_history.get_fixit_queue_ids().head(None) + if next_fixit_cmd and self._state.queue_status == QueueStatus.AWAITING_RECOVERY: + return next_fixit_cmd + # if there is a setup command queued, prioritize it next_setup_cmd = self._state.command_history.get_setup_queue_ids().head(None) - if self._state.queue_status != QueueStatus.PAUSED and next_setup_cmd: + if ( + self._state.queue_status + not in [QueueStatus.PAUSED, QueueStatus.AWAITING_RECOVERY] + and next_setup_cmd + ): return next_setup_cmd # if the queue is running, return the next protocol command @@ -814,12 +846,28 @@ def validate_action_allowed( # noqa: C901 raise SetupCommandNotAllowedError( "Setup commands are not allowed after run has started." ) + elif action.request.intent == CommandIntent.FIXIT: + if self._state.queue_status != QueueStatus.AWAITING_RECOVERY: + raise FixitCommandNotAllowedError( + "Fixit commands are not allowed when the run is not in a recoverable state." + ) + else: + return action else: return action elif isinstance(action, ResumeFromRecoveryAction): if self.get_status() != EngineStatus.AWAITING_RECOVERY: - raise NotImplementedError() + raise ResumeFromRecoveryNotAllowedError( + "Cannot resume from recovery if the run is not in recovery mode." + ) + elif ( + self.get_status() == EngineStatus.AWAITING_RECOVERY + and len(self._state.command_history.get_fixit_queue_ids()) > 0 + ): + raise ResumeFromRecoveryNotAllowedError( + "Cannot resume from recovery while there are fixit commands in the queue." + ) else: return action @@ -871,6 +919,6 @@ def get_status(self) -> EngineStatus: # SETUP and we're currently a setup command? return EngineStatus.IDLE - def get_latest_command_hash(self) -> Optional[str]: + def get_latest_protocol_command_hash(self) -> Optional[str]: """Get the command hash of the last queued command, if any.""" - return self._state.latest_command_hash + return self._state.latest_protocol_command_hash diff --git a/api/src/opentrons/protocol_engine/state/geometry.py b/api/src/opentrons/protocol_engine/state/geometry.py index 1822881eea2..112d7d60ef4 100644 --- a/api/src/opentrons/protocol_engine/state/geometry.py +++ b/api/src/opentrons/protocol_engine/state/geometry.py @@ -42,6 +42,7 @@ AddressableAreaLocation, AddressableOffsetVector, StagingSlotLocation, + LabwareOffsetLocation, ) from .config import Config from .labware import LabwareView @@ -166,6 +167,7 @@ def get_highest_z_in_slot( except LabwareNotLoadedOnModuleError: return self._modules.get_module_highest_z( module_id=module_id, + addressable_areas=self._addressable_areas, ) else: return self.get_highest_z_of_labware_stack(labware_id) @@ -246,7 +248,9 @@ def _get_labware_position_offset( return LabwareOffsetVector(x=0, y=0, z=0) elif isinstance(labware_location, ModuleLocation): module_id = labware_location.moduleId - module_offset = self._modules.get_nominal_module_offset(module_id=module_id) + module_offset = self._modules.get_nominal_module_offset( + module_id=module_id, addressable_areas=self._addressable_areas + ) module_model = self._modules.get_connected_model(module_id) stacking_overlap = self._labware.get_module_overlap_offsets( labware_id, module_model @@ -1087,3 +1091,48 @@ def _labware_gripper_offsets( return slot_based_offset or self._labware.get_labware_gripper_offsets( labware_id=labware_id, slot_name=None ) + + def get_offset_location(self, labware_id: str) -> Optional[LabwareOffsetLocation]: + """Provide the LabwareOffsetLocation specifying the current position of the labware. + + If the labware is in a location that cannot be specified by a LabwareOffsetLocation + (for instance, OFF_DECK) then return None. + """ + parent_location = self._labware.get_location(labware_id) + + if isinstance(parent_location, DeckSlotLocation): + return LabwareOffsetLocation( + slotName=parent_location.slotName, moduleModel=None, definitionUri=None + ) + elif isinstance(parent_location, ModuleLocation): + module_model = self._modules.get_requested_model(parent_location.moduleId) + module_location = self._modules.get_location(parent_location.moduleId) + return LabwareOffsetLocation( + slotName=module_location.slotName, + moduleModel=module_model, + definitionUri=None, + ) + elif isinstance(parent_location, OnLabwareLocation): + non_labware_parent_location = self._labware.get_parent_location(labware_id) + + parent_uri = self._labware.get_definition_uri(parent_location.labwareId) + if isinstance(non_labware_parent_location, DeckSlotLocation): + return LabwareOffsetLocation( + slotName=non_labware_parent_location.slotName, + moduleModel=None, + definitionUri=parent_uri, + ) + elif isinstance(non_labware_parent_location, ModuleLocation): + module_model = self._modules.get_requested_model( + non_labware_parent_location.moduleId + ) + module_location = self._modules.get_location( + non_labware_parent_location.moduleId + ) + return LabwareOffsetLocation( + slotName=module_location.slotName, + moduleModel=module_model, + definitionUri=parent_uri, + ) + + return None diff --git a/api/src/opentrons/protocol_engine/state/labware.py b/api/src/opentrons/protocol_engine/state/labware.py index 7709410fd0f..e9750a652b4 100644 --- a/api/src/opentrons/protocol_engine/state/labware.py +++ b/api/src/opentrons/protocol_engine/state/labware.py @@ -15,7 +15,7 @@ Union, ) -from opentrons_shared_data.deck.dev_types import DeckDefinitionV4 +from opentrons_shared_data.deck.dev_types import DeckDefinitionV5 from opentrons_shared_data.gripper.constants import LABWARE_GRIP_FORCE from opentrons_shared_data.labware.labware_definition import LabwareRole from opentrons_shared_data.pipette.dev_types import LabwareUri @@ -31,6 +31,7 @@ Command, LoadLabwareResult, MoveLabwareResult, + ReloadLabwareResult, ) from ..types import ( DeckSlotLocation, @@ -106,7 +107,7 @@ class LabwareState: labware_offsets_by_id: Dict[str, LabwareOffset] definitions_by_uri: Dict[str, LabwareDefinition] - deck_definition: DeckDefinitionV4 + deck_definition: DeckDefinitionV5 class LabwareStore(HasState[LabwareState], HandlesActions): @@ -116,7 +117,7 @@ class LabwareStore(HasState[LabwareState], HandlesActions): def __init__( self, - deck_definition: DeckDefinitionV4, + deck_definition: DeckDefinitionV5, deck_fixed_labware: Sequence[DeckFixedLabware], ) -> None: """Initialize a labware store and its state.""" @@ -187,18 +188,27 @@ def _handle_command(self, command: Command) -> None: ) self._state.definitions_by_uri[definition_uri] = command.result.definition + if isinstance(command.result, LoadLabwareResult): + location = command.params.location + else: + location = self._state.labware_by_id[command.result.labwareId].location self._state.labware_by_id[ command.result.labwareId ] = LoadedLabware.construct( id=command.result.labwareId, - location=command.params.location, + location=location, loadName=command.result.definition.parameters.loadName, definitionUri=definition_uri, offsetId=command.result.offsetId, displayName=command.params.displayName, ) + elif isinstance(command.result, ReloadLabwareResult): + labware_id = command.params.labwareId + new_offset_id = command.result.offsetId + self._state.labware_by_id[labware_id].offsetId = new_offset_id + elif isinstance(command.result, MoveLabwareResult): labware_id = command.params.labwareId new_location = command.params.newLocation @@ -324,7 +334,7 @@ def get_display_name(self, labware_id: str) -> str: or self.get_definition(labware_id).metadata.displayName ) - def get_deck_definition(self) -> DeckDefinitionV4: + def get_deck_definition(self) -> DeckDefinitionV5: """Get the current deck definition.""" return self._state.deck_definition diff --git a/api/src/opentrons/protocol_engine/state/modules.py b/api/src/opentrons/protocol_engine/state/modules.py index 84093de0d4a..0e79dd53cf2 100644 --- a/api/src/opentrons/protocol_engine/state/modules.py +++ b/api/src/opentrons/protocol_engine/state/modules.py @@ -46,6 +46,7 @@ DeckType, LabwareMovementOffsetData, ) +from .addressable_areas import AddressableAreaView from .. import errors from ..commands import ( Command, @@ -210,11 +211,12 @@ def handle_action(self, action: Action) -> None: def _handle_command(self, command: Command) -> None: if isinstance(command.result, LoadModuleResult): + slot_name = command.params.location.slotName self._add_module_substate( module_id=command.result.moduleId, serial_number=command.result.serialNumber, definition=command.result.definition, - slot_name=command.params.location.slotName, + slot_name=slot_name, requested_model=command.params.model, module_live_data=None, ) @@ -707,35 +709,70 @@ def get_dimensions(self, module_id: str) -> ModuleDimensions: def get_nominal_module_offset( self, module_id: str, + addressable_areas: AddressableAreaView, ) -> LabwareOffsetVector: """Get the module's nominal offset vector computed with slot transform.""" - definition = self.get_definition(module_id) - slot = self.get_location(module_id).slotName.id - - pre_transform: NDArray[npdouble] = array( - ( - definition.labwareOffset.x, - definition.labwareOffset.y, - definition.labwareOffset.z, - 1, + if ( + self.state.deck_type == DeckType.OT2_STANDARD + or self.state.deck_type == DeckType.OT2_SHORT_TRASH + ): + definition = self.get_definition(module_id) + slot = self.get_location(module_id).slotName.id + + pre_transform: NDArray[npdouble] = array( + ( + definition.labwareOffset.x, + definition.labwareOffset.y, + definition.labwareOffset.z, + 1, + ) + ) + xforms_ser = definition.slotTransforms.get( + str(self._state.deck_type.value), {} + ).get( + slot, + { + "labwareOffset": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 1], + ] + }, + ) + xforms_ser_offset = xforms_ser["labwareOffset"] + + # Apply the slot transform, if any + xform: NDArray[npdouble] = array(xforms_ser_offset) + xformed = dot(xform, pre_transform) + return LabwareOffsetVector( + x=xformed[0], + y=xformed[1], + z=xformed[2], + ) + else: + module = self.get(module_id) + if isinstance(module.location, DeckSlotLocation): + location = module.location.slotName + elif module.model == ModuleModel.THERMOCYCLER_MODULE_V2: + location = DeckSlotName.SLOT_B1 + else: + raise ValueError( + "Module location invalid for nominal module offset calculation." + ) + module_addressable_area = self.ensure_and_convert_module_fixture_location( + location, self.state.deck_type, module.model + ) + module_addressable_area_position = ( + addressable_areas.get_addressable_area_offsets_from_cutout( + module_addressable_area + ) + ) + return LabwareOffsetVector( + x=module_addressable_area_position.x, + y=module_addressable_area_position.y, + z=module_addressable_area_position.z, ) - ) - xforms_ser = definition.slotTransforms.get( - str(self._state.deck_type.value), {} - ).get( - slot, - {"labwareOffset": [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]}, - ) - xforms_ser_offset = xforms_ser["labwareOffset"] - - # Apply the slot transform, if any - xform: NDArray[npdouble] = array(xforms_ser_offset) - xformed = dot(xform, pre_transform) - return LabwareOffsetVector( - x=xformed[0], - y=xformed[1], - z=xformed[2], - ) def get_module_calibration_offset( self, module_id: str @@ -755,7 +792,9 @@ def get_height_over_labware(self, module_id: str) -> float: """Get the height of module parts above module labware base.""" return self.get_dimensions(module_id).overLabwareHeight - def get_module_highest_z(self, module_id: str) -> float: + def get_module_highest_z( + self, module_id: str, addressable_areas: AddressableAreaView + ) -> float: """Get the highest z point of the module, as placed on the robot. The highest Z of a module, unlike the bare overall height, depends on @@ -781,7 +820,7 @@ def get_module_highest_z(self, module_id: str) -> float: z_difference = module_height - default_lw_offset_point nominal_transformed_lw_offset_z = self.get_nominal_module_offset( - module_id=module_id + module_id=module_id, addressable_areas=addressable_areas ).z calibration_offset = self.get_module_calibration_offset(module_id) return ( @@ -943,11 +982,12 @@ def is_edge_move_unsafe(self, mount: MountType, target_slot: DeckSlotName) -> bo return neighbor_slot in self._state.slot_by_module_id.values() - def select_hardware_module_to_load( + def select_hardware_module_to_load( # noqa: C901 self, model: ModuleModel, location: DeckSlotLocation, attached_modules: Sequence[HardwareModule], + expected_serial_number: Optional[str] = None, ) -> HardwareModule: """Get the next matching hardware module for the given model and location. @@ -963,6 +1003,8 @@ def select_hardware_module_to_load( location: The location the module will be assigned to. attached_modules: All attached modules as reported by the HardwareAPI, in the order in which they should be used. + expected_serial_number: An optional variable containing the serial number + expected of the module identified. Raises: ModuleNotAttachedError: A not-yet-assigned module matching the requested @@ -976,7 +1018,6 @@ def select_hardware_module_to_load( if slot == location.slotName: existing_mod_in_slot = self._state.hardware_by_module_id.get(mod_id) break - if existing_mod_in_slot: existing_def = existing_mod_in_slot.definition @@ -992,7 +1033,11 @@ def select_hardware_module_to_load( for m in attached_modules: if m not in self._state.hardware_by_module_id.values(): if model == m.definition.model or model in m.definition.compatibleWith: - return m + if expected_serial_number is not None: + if m.serial_number == expected_serial_number: + return m + else: + return m raise errors.ModuleNotAttachedError(f"No available {model.value} found.") @@ -1063,3 +1108,92 @@ def is_flex_deck_with_thermocycler(self) -> bool: return True else: return False + + def ensure_and_convert_module_fixture_location( + self, + deck_slot: DeckSlotName, + deck_type: DeckType, + model: ModuleModel, + ) -> str: + """Ensure module fixture load location is valid. + + Also, convert the deck slot to a valid module fixture addressable area. + """ + if deck_type == DeckType.OT2_STANDARD or deck_type == DeckType.OT2_SHORT_TRASH: + raise ValueError( + f"Invalid Deck Type: {deck_type.name} - Does not support modules as fixtures." + ) + + if model == ModuleModel.MAGNETIC_BLOCK_V1: + valid_slots = [ + slot + for slot in [ + "A1", + "B1", + "C1", + "D1", + "A2", + "B2", + "C2", + "D2", + "A3", + "B3", + "C3", + "D3", + ] + ] + addressable_areas = [ + "magneticBlockV1A1", + "magneticBlockV1B1", + "magneticBlockV1C1", + "magneticBlockV1D1", + "magneticBlockV1A2", + "magneticBlockV1B2", + "magneticBlockV1C2", + "magneticBlockV1D2", + "magneticBlockV1A3", + "magneticBlockV1B3", + "magneticBlockV1C3", + "magneticBlockV1D3", + ] + + elif model == ModuleModel.HEATER_SHAKER_MODULE_V1: + valid_slots = [ + slot for slot in ["A1", "B1", "C1", "D1", "A3", "B3", "C3", "D3"] + ] + addressable_areas = [ + "heaterShakerV1A1", + "heaterShakerV1B1", + "heaterShakerV1C1", + "heaterShakerV1D1", + "heaterShakerV1A3", + "heaterShakerV1B3", + "heaterShakerV1C3", + "heaterShakerV1D3", + ] + elif model == ModuleModel.TEMPERATURE_MODULE_V2: + valid_slots = [ + slot for slot in ["A1", "B1", "C1", "D1", "A3", "B3", "C3", "D3"] + ] + addressable_areas = [ + "temperatureModuleV2A1", + "temperatureModuleV2B1", + "temperatureModuleV2C1", + "temperatureModuleV2D1", + "temperatureModuleV2A3", + "temperatureModuleV2B3", + "temperatureModuleV2C3", + "temperatureModuleV2D3", + ] + elif model == ModuleModel.THERMOCYCLER_MODULE_V2: + return "thermocyclerModuleV2" + else: + raise ValueError( + f"Unknown module {model.name} has no addressable areas to provide." + ) + + map_addressable_area = { + slot: addressable_area + for slot, addressable_area in zip(valid_slots, addressable_areas) + } + return map_addressable_area[deck_slot.value] diff --git a/api/src/opentrons/protocol_engine/state/state.py b/api/src/opentrons/protocol_engine/state/state.py index 6e08bf759c6..aa54383b379 100644 --- a/api/src/opentrons/protocol_engine/state/state.py +++ b/api/src/opentrons/protocol_engine/state/state.py @@ -5,14 +5,14 @@ from typing import Callable, Dict, List, Optional, Sequence, TypeVar from typing_extensions import ParamSpec -from opentrons_shared_data.deck.dev_types import DeckDefinitionV4 +from opentrons_shared_data.deck.dev_types import DeckDefinitionV5 from opentrons.protocol_engine.types import ModuleOffsetData +from opentrons.util.change_notifier import ChangeNotifier from ..resources import DeckFixedLabware from ..actions import Action, ActionHandler from .abstract_store import HasState, HandlesActions -from .change_notifier import ChangeNotifier from .commands import CommandState, CommandStore, CommandView from .addressable_areas import ( AddressableAreaState, @@ -142,7 +142,7 @@ def __init__( self, *, config: Config, - deck_definition: DeckDefinitionV4, + deck_definition: DeckDefinitionV5, deck_fixed_labware: Sequence[DeckFixedLabware], is_door_open: bool, change_notifier: Optional[ChangeNotifier] = None, diff --git a/api/src/opentrons/protocol_engine/types.py b/api/src/opentrons/protocol_engine/types.py index 3d833a65042..13e9515e447 100644 --- a/api/src/opentrons/protocol_engine/types.py +++ b/api/src/opentrons/protocol_engine/types.py @@ -10,7 +10,10 @@ from opentrons_shared_data.pipette.dev_types import PipetteNameType from opentrons.types import MountType, DeckSlotName, StagingSlotName -from opentrons.hardware_control.types import TipStateType as HwTipStateType +from opentrons.hardware_control.types import ( + TipStateType as HwTipStateType, + InstrumentProbeType, +) from opentrons.hardware_control.modules import ( ModuleType as ModuleType, ) @@ -714,6 +717,10 @@ class AreaType(Enum): MOVABLE_TRASH = "movableTrash" FIXED_TRASH = "fixedTrash" WASTE_CHUTE = "wasteChute" + THERMOCYCLER = "thermocycler" + HEATER_SHAKER = "heaterShaker" + TEMPERATURE = "temperatureModule" + MAGNETICBLOCK = "magneticBlock" @dataclass(frozen=True) @@ -820,7 +827,26 @@ class QuadrantNozzleLayoutConfiguration(BaseModel): ] # TODO make the below some sort of better type -DeckConfigurationType = List[Tuple[str, str]] # cutout_id, cutout_fixture_id +# TODO This should instead contain a proper cutout fixture type +DeckConfigurationType = List[ + Tuple[str, str, Optional[str]] +] # cutout_id, cutout_fixture_id, opentrons_module_serial_number + + +class InstrumentSensorId(str, Enum): + """Primary and secondary sensor ids.""" + + PRIMARY = "primary" + SECONDARY = "secondary" + BOTH = "both" + + def to_instrument_probe_type(self) -> InstrumentProbeType: + """Convert to InstrumentProbeType.""" + return { + InstrumentSensorId.PRIMARY: InstrumentProbeType.PRIMARY, + InstrumentSensorId.SECONDARY: InstrumentProbeType.SECONDARY, + InstrumentSensorId.BOTH: InstrumentProbeType.BOTH, + }[self] class TipPresenceStatus(str, Enum): diff --git a/api/src/opentrons/protocol_runner/create_simulating_runner.py b/api/src/opentrons/protocol_runner/create_simulating_runner.py index 0c60af3a45c..392afa512f7 100644 --- a/api/src/opentrons/protocol_runner/create_simulating_runner.py +++ b/api/src/opentrons/protocol_runner/create_simulating_runner.py @@ -1,6 +1,5 @@ """Simulating AbstractRunner factory.""" -from opentrons.config import feature_flags from opentrons.hardware_control import API as OT2API, HardwareControlAPI from opentrons.protocols.api_support import deck_type from opentrons.protocols.api_support.deck_type import should_load_fixed_trash @@ -13,7 +12,7 @@ from opentrons_shared_data.robot.dev_types import RobotType -from .legacy_wrappers import LegacySimulatingContextCreator +from .python_protocol_wrappers import SimulatingContextCreator from .protocol_runner import create_protocol_runner, AbstractRunner @@ -58,12 +57,12 @@ async def create_simulating_runner( use_virtual_modules=True, use_virtual_gripper=True, use_simulated_deck_config=True, - use_virtual_pipettes=(not feature_flags.disable_fast_protocol_upload()), + use_virtual_pipettes=True, ), load_fixed_trash=should_load_fixed_trash(protocol_config), ) - simulating_legacy_context_creator = LegacySimulatingContextCreator( + simulating_context_creator = SimulatingContextCreator( hardware_api=simulating_hardware_api, protocol_engine=protocol_engine, ) @@ -72,7 +71,7 @@ async def create_simulating_runner( protocol_config=protocol_config, protocol_engine=protocol_engine, hardware_api=simulating_hardware_api, - legacy_context_creator=simulating_legacy_context_creator, + protocol_context_creator=simulating_context_creator, ) diff --git a/api/src/opentrons/protocol_runner/legacy_command_mapper.py b/api/src/opentrons/protocol_runner/legacy_command_mapper.py index e835a6af8e6..ababa892616 100644 --- a/api/src/opentrons/protocol_runner/legacy_command_mapper.py +++ b/api/src/opentrons/protocol_runner/legacy_command_mapper.py @@ -4,9 +4,24 @@ from datetime import datetime from typing import Dict, List, Optional, Tuple, Union +from opentrons.hardware_control.modules.types import ( + ModuleModel as HardwareModuleModel, + TemperatureModuleModel, + MagneticModuleModel, + ThermocyclerModuleModel, + HeaterShakerModuleModel, +) from opentrons_shared_data.pipette.dev_types import PipetteNameType from opentrons.types import MountType, DeckSlotName, Location from opentrons.legacy_commands import types as legacy_command_types +from opentrons.protocol_api import InstrumentContext +from opentrons.protocol_api.core.legacy.deck import FIXED_TRASH_ID +from opentrons.protocol_api.core.legacy.load_info import ( + LoadInfo as LegacyLoadInfo, + LabwareLoadInfo as LegacyLabwareLoadInfo, + InstrumentLoadInfo as LegacyInstrumentLoadInfo, + ModuleLoadInfo as LegacyModuleLoadInfo, +) from opentrons.protocol_engine import ( ProtocolEngineError, actions as pe_actions, @@ -19,22 +34,9 @@ ModuleDataProvider, pipette_data_provider, ) + from opentrons_shared_data.labware.labware_definition import LabwareDefinition from opentrons_shared_data.errors import ErrorCodes, EnumeratedError, PythonException -from opentrons.protocol_api.core.legacy.deck import FIXED_TRASH_ID - -from .legacy_wrappers import ( - LegacyLoadInfo, - LegacyInstrumentLoadInfo, - LegacyLabwareLoadInfo, - LegacyModuleLoadInfo, - LegacyPipetteContext, - LegacyModuleModel, - LegacyMagneticModuleModel, - LegacyTemperatureModuleModel, - LegacyThermocyclerModuleModel, - LegacyHeaterShakerModuleModel, -) class LegacyCommandParams(pe_commands.CustomParams): @@ -63,14 +65,14 @@ def __init__(self, wrapping_exc: BaseException) -> None: ) -_LEGACY_TO_PE_MODULE: Dict[LegacyModuleModel, pe_types.ModuleModel] = { - LegacyMagneticModuleModel.MAGNETIC_V1: pe_types.ModuleModel.MAGNETIC_MODULE_V1, - LegacyMagneticModuleModel.MAGNETIC_V2: pe_types.ModuleModel.MAGNETIC_MODULE_V2, - LegacyTemperatureModuleModel.TEMPERATURE_V1: pe_types.ModuleModel.TEMPERATURE_MODULE_V1, - LegacyTemperatureModuleModel.TEMPERATURE_V2: pe_types.ModuleModel.TEMPERATURE_MODULE_V2, - LegacyThermocyclerModuleModel.THERMOCYCLER_V1: pe_types.ModuleModel.THERMOCYCLER_MODULE_V1, - LegacyThermocyclerModuleModel.THERMOCYCLER_V2: pe_types.ModuleModel.THERMOCYCLER_MODULE_V2, - LegacyHeaterShakerModuleModel.HEATER_SHAKER_V1: pe_types.ModuleModel.HEATER_SHAKER_MODULE_V1, +_HARDWARE_TO_PE_MODULE: Dict[HardwareModuleModel, pe_types.ModuleModel] = { + MagneticModuleModel.MAGNETIC_V1: pe_types.ModuleModel.MAGNETIC_MODULE_V1, + MagneticModuleModel.MAGNETIC_V2: pe_types.ModuleModel.MAGNETIC_MODULE_V2, + TemperatureModuleModel.TEMPERATURE_V1: pe_types.ModuleModel.TEMPERATURE_MODULE_V1, + TemperatureModuleModel.TEMPERATURE_V2: pe_types.ModuleModel.TEMPERATURE_MODULE_V2, + ThermocyclerModuleModel.THERMOCYCLER_V1: pe_types.ModuleModel.THERMOCYCLER_MODULE_V1, + ThermocyclerModuleModel.THERMOCYCLER_V2: pe_types.ModuleModel.THERMOCYCLER_MODULE_V2, + HeaterShakerModuleModel.HEATER_SHAKER_V1: pe_types.ModuleModel.HEATER_SHAKER_MODULE_V1, } _HIGHER_ORDER_COMMAND_TYPES = { @@ -79,6 +81,7 @@ def __init__(self, wrapping_exc: BaseException) -> None: legacy_command_types.DISTRIBUTE, legacy_command_types.TRANSFER, legacy_command_types.RETURN_TIP, + legacy_command_types.AIR_GAP, } @@ -353,7 +356,7 @@ def _build_drop_tip( command_id: str, now: datetime, ) -> Tuple[pe_commands.CommandCreate, pe_commands.Command]: - pipette: LegacyPipetteContext = command["payload"]["instrument"] + pipette: InstrumentContext = command["payload"]["instrument"] well = command["payload"]["location"] mount = MountType(pipette.mount) # the following type checking suppression assumes the tiprack is not loaded on top of a module @@ -386,7 +389,7 @@ def _build_pick_up_tip( command_id: str, now: datetime, ) -> Tuple[pe_commands.CommandCreate, pe_commands.Command]: - pipette: LegacyPipetteContext = command["payload"]["instrument"] + pipette: InstrumentContext = command["payload"]["instrument"] location = command["payload"]["location"] well = location mount = MountType(pipette.mount) @@ -421,7 +424,7 @@ def _build_liquid_handling( command_id: str, now: datetime, ) -> Tuple[pe_commands.CommandCreate, pe_commands.Command]: - pipette: LegacyPipetteContext = command["payload"]["instrument"] + pipette: InstrumentContext = command["payload"]["instrument"] location = command["payload"]["location"] volume = command["payload"]["volume"] # TODO:(jr, 15.08.2022): aspirate and dispense commands with no specified labware @@ -532,7 +535,7 @@ def _build_blow_out( command_id: str, now: datetime, ) -> Tuple[pe_commands.CommandCreate, pe_commands.Command]: - pipette: LegacyPipetteContext = command["payload"]["instrument"] + pipette: InstrumentContext = command["payload"]["instrument"] location = command["payload"]["location"] flow_rate = pipette.flow_rate.blow_out # TODO:(jr, 15.08.2022): blow_out commands with no specified labware get filtered @@ -724,8 +727,8 @@ def _map_module_load( count = self._command_count["LOAD_MODULE"] command_id = f"commands.LOAD_MODULE-{count}" module_id = f"module-{count}" - requested_model = _LEGACY_TO_PE_MODULE[module_load_info.requested_model] - loaded_model = _LEGACY_TO_PE_MODULE[module_load_info.loaded_model] + requested_model = _HARDWARE_TO_PE_MODULE[module_load_info.requested_model] + loaded_model = _HARDWARE_TO_PE_MODULE[module_load_info.loaded_model] # This will fetch a V2 definition only. PAPI < v2.3 use V1 definitions. # When running a < v2.3 protocol, there will be a mismatch of definitions used diff --git a/api/src/opentrons/protocol_runner/legacy_context_plugin.py b/api/src/opentrons/protocol_runner/legacy_context_plugin.py index 7dd882f0fb7..baf6ccbc716 100644 --- a/api/src/opentrons/protocol_runner/legacy_context_plugin.py +++ b/api/src/opentrons/protocol_runner/legacy_context_plugin.py @@ -7,10 +7,10 @@ from opentrons.legacy_commands.types import CommandMessage as LegacyCommand from opentrons.legacy_broker import LegacyBroker +from opentrons.protocol_api.core.legacy.load_info import LoadInfo from opentrons.protocol_engine import AbstractPlugin, actions as pe_actions from opentrons.util.broker import ReadOnlyBroker -from .legacy_wrappers import LegacyLoadInfo from .legacy_command_mapper import LegacyCommandMapper from .thread_async_queue import ThreadAsyncQueue @@ -37,7 +37,7 @@ class LegacyContextPlugin(AbstractPlugin): def __init__( self, broker: LegacyBroker, - equipment_broker: ReadOnlyBroker[LegacyLoadInfo], + equipment_broker: ReadOnlyBroker[LoadInfo], legacy_command_mapper: Optional[LegacyCommandMapper] = None, ) -> None: """Initialize the plugin with its dependencies.""" @@ -122,15 +122,15 @@ def handle_action(self, action: pe_actions.Action) -> None: pass def _handle_legacy_command(self, command: LegacyCommand) -> None: - """Handle a command reported by the APIv2 protocol. + """Handle a command reported by the legacy APIv2 protocol. Used as a broker callback, so this will run in the APIv2 protocol's thread. """ pe_actions = self._legacy_command_mapper.map_command(command=command) self._actions_to_dispatch.put(pe_actions) - def _handle_equipment_loaded(self, load_info: LegacyLoadInfo) -> None: - """Handle an equipment load reported by the APIv2 protocol. + def _handle_equipment_loaded(self, load_info: LoadInfo) -> None: + """Handle an equipment load reported by the legacy APIv2 protocol. Used as a broker callback, so this will run in the APIv2 protocol's thread. """ diff --git a/api/src/opentrons/protocol_runner/protocol_runner.py b/api/src/opentrons/protocol_runner/protocol_runner.py index a1e88969615..5a8b9134772 100644 --- a/api/src/opentrons/protocol_runner/protocol_runner.py +++ b/api/src/opentrons/protocol_runner/protocol_runner.py @@ -10,6 +10,7 @@ from opentrons import protocol_reader from opentrons.legacy_broker import LegacyBroker from opentrons.protocol_api import ParameterContext +from opentrons.protocol_api.core.legacy.load_info import LoadInfo from opentrons.protocol_reader import ( ProtocolSource, JsonProtocolConfig, @@ -28,13 +29,12 @@ from .json_file_reader import JsonFileReader from .json_translator import JsonTranslator from .legacy_context_plugin import LegacyContextPlugin -from .legacy_wrappers import ( +from .python_protocol_wrappers import ( LEGACY_PYTHON_API_VERSION_CUTOFF, LEGACY_JSON_SCHEMA_VERSION_CUTOFF, - LegacyFileReader, - LegacyContextCreator, - LegacyExecutor, - LegacyLoadInfo, + PythonAndLegacyFileReader, + ProtocolContextCreator, + PythonProtocolExecutor, ) from ..protocol_engine.errors import ProtocolCommandFailedError from ..protocol_engine.types import ( @@ -101,12 +101,12 @@ def play(self, deck_configuration: Optional[DeckConfigurationType] = None) -> No def pause(self) -> None: """Pause the run.""" - self._protocol_engine.pause() + self._protocol_engine.request_pause() async def stop(self) -> None: """Stop (cancel) the run.""" if self.was_started(): - await self._protocol_engine.stop() + await self._protocol_engine.request_stop() else: await self._protocol_engine.finish( drop_tips_after_run=False, @@ -136,21 +136,26 @@ def __init__( protocol_engine: ProtocolEngine, hardware_api: HardwareControlAPI, task_queue: Optional[TaskQueue] = None, - legacy_file_reader: Optional[LegacyFileReader] = None, - legacy_context_creator: Optional[LegacyContextCreator] = None, - legacy_executor: Optional[LegacyExecutor] = None, + python_and_legacy_file_reader: Optional[PythonAndLegacyFileReader] = None, + protocol_context_creator: Optional[ProtocolContextCreator] = None, + python_protocol_executor: Optional[PythonProtocolExecutor] = None, post_run_hardware_state: PostRunHardwareState = PostRunHardwareState.HOME_AND_STAY_ENGAGED, drop_tips_after_run: bool = True, ) -> None: """Initialize the PythonAndLegacyRunner with its dependencies.""" super().__init__(protocol_engine) self._hardware_api = hardware_api - self._legacy_file_reader = legacy_file_reader or LegacyFileReader() - self._legacy_context_creator = legacy_context_creator or LegacyContextCreator( - hardware_api=hardware_api, - protocol_engine=protocol_engine, + self._protocol_file_reader = ( + python_and_legacy_file_reader or PythonAndLegacyFileReader() ) - self._legacy_executor = legacy_executor or LegacyExecutor() + self._protocol_context_creator = ( + protocol_context_creator + or ProtocolContextCreator( + hardware_api=hardware_api, + protocol_engine=protocol_engine, + ) + ) + self._protocol_executor = python_protocol_executor or PythonProtocolExecutor() # TODO(mc, 2022-01-11): replace task queue with specific implementations # of runner interface self._task_queue = task_queue or TaskQueue() @@ -185,14 +190,14 @@ async def load( # fixme(mm, 2022-12-23): This does I/O and compute-bound parsing that will block # the event loop. Jira RSS-165. - protocol = self._legacy_file_reader.read( + protocol = self._protocol_file_reader.read( protocol_source, labware_definitions, python_parse_mode ) self._parameter_context = ParameterContext(api_version=protocol.api_level) equipment_broker = None if protocol.api_level < LEGACY_PYTHON_API_VERSION_CUTOFF: - equipment_broker = Broker[LegacyLoadInfo]() + equipment_broker = Broker[LoadInfo]() self._protocol_engine.add_plugin( LegacyContextPlugin( broker=self._broker, equipment_broker=equipment_broker @@ -202,7 +207,7 @@ async def load( else: self._hardware_api.should_taskify_movement_execution(taskify=False) - context = self._legacy_context_creator.create( + context = self._protocol_context_creator.create( protocol=protocol, broker=self._broker, equipment_broker=equipment_broker, @@ -216,7 +221,7 @@ async def run_func() -> None: await self._protocol_engine.add_and_execute_command( request=initial_home_command ) - await self._legacy_executor.execute( + await self._protocol_executor.execute( protocol=protocol, context=context, parameter_context=self._parameter_context, @@ -417,9 +422,9 @@ def create_protocol_runner( task_queue: Optional[TaskQueue] = None, json_file_reader: Optional[JsonFileReader] = None, json_translator: Optional[JsonTranslator] = None, - legacy_file_reader: Optional[LegacyFileReader] = None, - legacy_context_creator: Optional[LegacyContextCreator] = None, - legacy_executor: Optional[LegacyExecutor] = None, + python_and_legacy_file_reader: Optional[PythonAndLegacyFileReader] = None, + protocol_context_creator: Optional[ProtocolContextCreator] = None, + python_protocol_executor: Optional[PythonProtocolExecutor] = None, post_run_hardware_state: PostRunHardwareState = PostRunHardwareState.HOME_AND_STAY_ENGAGED, drop_tips_after_run: bool = True, ) -> AnyRunner: @@ -443,9 +448,9 @@ def create_protocol_runner( protocol_engine=protocol_engine, hardware_api=hardware_api, task_queue=task_queue, - legacy_file_reader=legacy_file_reader, - legacy_context_creator=legacy_context_creator, - legacy_executor=legacy_executor, + python_and_legacy_file_reader=python_and_legacy_file_reader, + protocol_context_creator=protocol_context_creator, + python_protocol_executor=python_protocol_executor, post_run_hardware_state=post_run_hardware_state, drop_tips_after_run=drop_tips_after_run, ) diff --git a/api/src/opentrons/protocol_runner/legacy_wrappers.py b/api/src/opentrons/protocol_runner/python_protocol_wrappers.py similarity index 63% rename from api/src/opentrons/protocol_runner/legacy_wrappers.py rename to api/src/opentrons/protocol_runner/python_protocol_wrappers.py index 9783c877227..e0a345db0f0 100644 --- a/api/src/opentrons/protocol_runner/legacy_wrappers.py +++ b/api/src/opentrons/protocol_runner/python_protocol_wrappers.py @@ -1,23 +1,16 @@ -"""Wrappers for the legacy, Protocol API v2 execution pipeline.""" +"""Wrappers for Protocol API v2 execution pipeline.""" import asyncio from typing import Dict, Iterable, Optional, cast from anyio import to_thread from opentrons_shared_data.labware.dev_types import ( - LabwareDefinition as LegacyLabwareDefinition, + LabwareDefinition as LabwareDefinitionTypedDict, ) from opentrons_shared_data.labware.labware_definition import LabwareDefinition from opentrons.calibration_storage.helpers import uri_from_details from opentrons.hardware_control import HardwareControlAPI -from opentrons.hardware_control.modules.types import ( - ModuleModel as LegacyModuleModel, - TemperatureModuleModel as LegacyTemperatureModuleModel, - MagneticModuleModel as LegacyMagneticModuleModel, - ThermocyclerModuleModel as LegacyThermocyclerModuleModel, - HeaterShakerModuleModel as LegacyHeaterShakerModuleModel, -) from opentrons.legacy_broker import LegacyBroker from opentrons.protocol_engine import ProtocolEngine from opentrons.protocol_engine.types import RunTimeParamValuesType @@ -25,32 +18,20 @@ from opentrons.util.broker import Broker from opentrons.protocol_api import ( - ProtocolContext as LegacyProtocolContext, - InstrumentContext as LegacyPipetteContext, - ModuleContext as LegacyModuleContext, - Labware as LegacyLabware, - Well as LegacyWell, + ProtocolContext, ParameterContext, create_protocol_context, ) from opentrons.protocol_api.core.engine import ENGINE_CORE_API_VERSION -from opentrons.protocol_api.core.legacy.load_info import ( - LoadInfo as LegacyLoadInfo, - InstrumentLoadInfo as LegacyInstrumentLoadInfo, - LabwareLoadInfo as LegacyLabwareLoadInfo, - ModuleLoadInfo as LegacyModuleLoadInfo, -) +from opentrons.protocol_api.core.legacy.load_info import LoadInfo from opentrons.protocols.parse import PythonParseMode, parse from opentrons.protocols.execution.execute import run_protocol -from opentrons.protocols.types import ( - Protocol as LegacyProtocol, - JsonProtocol as LegacyJsonProtocol, - PythonProtocol as LegacyPythonProtocol, -) +from opentrons.protocols.types import Protocol, PythonProtocol + # The earliest Python Protocol API version ("apiLevel") where the protocol's simulation -# and execution will be handled by Protocol Engine, rather than the legacy machinery. +# and execution will be handled by Protocol Engine, rather than the previous direct hardware calls from protocol api. # # Note that even when simulation and execution are handled by the legacy machinery, # Protocol Engine still has some involvement for analyzing the simulation and @@ -63,7 +44,7 @@ LEGACY_JSON_SCHEMA_VERSION_CUTOFF = 6 -class LegacyFileReader: +class PythonAndLegacyFileReader: """Interface to read Protocol API v2 protocols prior to execution.""" @staticmethod @@ -71,16 +52,16 @@ def read( protocol_source: ProtocolSource, labware_definitions: Iterable[LabwareDefinition], python_parse_mode: PythonParseMode, - ) -> LegacyProtocol: + ) -> Protocol: """Read a PAPIv2 protocol into a data structure.""" protocol_file_path = protocol_source.main_file protocol_contents = protocol_file_path.read_text(encoding="utf-8") - legacy_labware_definitions: Dict[str, LegacyLabwareDefinition] = { + extra_labware: Dict[str, LabwareDefinitionTypedDict] = { uri_from_details( namespace=lw.namespace, load_name=lw.parameters.loadName, version=lw.version, - ): cast(LegacyLabwareDefinition, lw.dict(exclude_none=True)) + ): cast(LabwareDefinitionTypedDict, lw.dict(exclude_none=True)) for lw in labware_definitions } data_file_paths = [ @@ -92,7 +73,7 @@ def read( return parse( protocol_file=protocol_contents, filename=protocol_file_path.name, - extra_labware=legacy_labware_definitions, + extra_labware=extra_labware, extra_data={ data_path.name: data_path.read_bytes() for data_path in data_file_paths }, @@ -100,9 +81,7 @@ def read( ) -# TODO (spp, 2023-04-05): Remove 'legacy' wording since this is the context we are using -# for all python protocols. -class LegacyContextCreator: +class ProtocolContextCreator: """Interface to construct Protocol API v2 contexts.""" _USE_SIMULATING_CORE = False @@ -125,21 +104,17 @@ def __init__( def create( self, - protocol: LegacyProtocol, + protocol: Protocol, broker: Optional[LegacyBroker], - equipment_broker: Optional[Broker[LegacyLoadInfo]], - ) -> LegacyProtocolContext: + equipment_broker: Optional[Broker[LoadInfo]], + ) -> ProtocolContext: """Create a Protocol API v2 context.""" extra_labware = ( - protocol.extra_labware - if isinstance(protocol, LegacyPythonProtocol) - else None + protocol.extra_labware if isinstance(protocol, PythonProtocol) else None ) bundled_data = ( - protocol.bundled_data - if isinstance(protocol, LegacyPythonProtocol) - else None + protocol.bundled_data if isinstance(protocol, PythonProtocol) else None ) return create_protocol_context( @@ -156,7 +131,7 @@ def create( ) -class LegacySimulatingContextCreator(LegacyContextCreator): +class SimulatingContextCreator(ProtocolContextCreator): """Interface to construct PAPIv2 contexts using simulating implementations. Avoids some calls to the hardware API for performance. @@ -166,13 +141,13 @@ class LegacySimulatingContextCreator(LegacyContextCreator): _USE_SIMULATING_CORE = True -class LegacyExecutor: +class PythonProtocolExecutor: """Interface to execute Protocol API v2 protocols in a child thread.""" @staticmethod async def execute( - protocol: LegacyProtocol, - context: LegacyProtocolContext, + protocol: Protocol, + context: ProtocolContext, parameter_context: Optional[ParameterContext], run_time_param_values: Optional[RunTimeParamValuesType], ) -> None: @@ -180,29 +155,3 @@ async def execute( await to_thread.run_sync( run_protocol, protocol, context, parameter_context, run_time_param_values ) - - -__all__ = [ - # Re-exports of user-facing Python Protocol APIv2 stuff: - # TODO(mc, 2022-08-22): remove, no longer "legacy", so re-exports unnecessary - "LegacyProtocolContext", - "LegacyLabware", - "LegacyWell", - "LegacyPipetteContext", - "LegacyModuleContext", - # Re-exports of internal stuff: - "LegacyProtocol", - "LegacyJsonProtocol", - "LegacyPythonProtocol", - "LegacyLoadInfo", - "LegacyLabwareLoadInfo", - "LegacyInstrumentLoadInfo", - "LegacyModuleLoadInfo", - "LegacyModuleModel", - "LegacyMagneticModuleModel", - "LegacyTemperatureModuleModel", - "LegacyThermocyclerModuleModel", - "LegacyHeaterShakerModuleModel", - # legacy typed dicts - "LegacyLabwareDefinition", -] diff --git a/api/src/opentrons/protocols/parameters/validation.py b/api/src/opentrons/protocols/parameters/validation.py index 166055df504..8e7a0bed8ad 100644 --- a/api/src/opentrons/protocols/parameters/validation.py +++ b/api/src/opentrons/protocols/parameters/validation.py @@ -1,5 +1,5 @@ import keyword -from typing import List, Optional, Union, Literal +from typing import List, Set, Optional, Union, Literal from .types import ( AllowedTypes, @@ -16,17 +16,34 @@ DESCRIPTION_MAX_LEN = 100 +def validate_variable_name_unique( + variable_name: str, other_variable_names: Set[str] +) -> None: + """Validate that the given variable name is unique.""" + if isinstance(variable_name, str) and variable_name in other_variable_names: + raise ParameterNameError( + f'"{variable_name}" is already defined as a variable name for another parameter.' + f" All variable names must be unique." + ) + + def ensure_display_name(display_name: str) -> str: """Validate display name is within the character limit.""" + if not isinstance(display_name, str): + raise ParameterNameError( + f"Display name must be a string and at most {DISPLAY_NAME_MAX_LEN} characters." + ) if len(display_name) > DISPLAY_NAME_MAX_LEN: raise ParameterNameError( - f"Display name {display_name} greater than {DISPLAY_NAME_MAX_LEN} characters." + f'Display name "{display_name}" greater than {DISPLAY_NAME_MAX_LEN} characters.' ) return display_name def ensure_variable_name(variable_name: str) -> str: """Validate variable name is a valid python variable name.""" + if not isinstance(variable_name, str): + raise ParameterNameError("Variable name must be a string.") if not variable_name.isidentifier(): raise ParameterNameError( "Variable name must only contain alphanumeric characters, underscores, and cannot start with a digit." @@ -38,19 +55,29 @@ def ensure_variable_name(variable_name: str) -> str: def ensure_description(description: Optional[str]) -> Optional[str]: """Validate description is within the character limit.""" - if description is not None and len(description) > DESCRIPTION_MAX_LEN: - raise ParameterNameError( - f"Description {description} greater than {DESCRIPTION_MAX_LEN} characters." - ) + if description is not None: + if not isinstance(description, str): + raise ParameterNameError( + f"Description must be a string and at most {DESCRIPTION_MAX_LEN} characters." + ) + if len(description) > DESCRIPTION_MAX_LEN: + raise ParameterNameError( + f'Description "{description}" greater than {DESCRIPTION_MAX_LEN} characters.' + ) return description def ensure_unit_string_length(unit: Optional[str]) -> Optional[str]: """Validate unit is within the character limit.""" - if unit is not None and len(unit) > UNIT_MAX_LEN: - raise ParameterNameError( - f"Description {unit} greater than {UNIT_MAX_LEN} characters." - ) + if unit is not None: + if not isinstance(unit, str): + raise ParameterNameError( + f"Unit must be a string and at most {UNIT_MAX_LEN} characters." + ) + if len(unit) > UNIT_MAX_LEN: + raise ParameterNameError( + f'Unit "{unit}" greater than {UNIT_MAX_LEN} characters.' + ) return unit @@ -124,7 +151,7 @@ def convert_type_string_for_enum( return "str" else: raise ParameterValueError( - f"Cannot resolve parameter type {parameter_type} for an enumerated parameter." + f"Cannot resolve parameter type '{parameter_type.__name__}' for an enumerated parameter." ) @@ -136,7 +163,7 @@ def convert_type_string_for_num_param(parameter_type: type) -> Literal["int", "f return "float" else: raise ParameterValueError( - f"Cannot resolve parameter type {parameter_type} for a number parameter." + f"Cannot resolve parameter type '{parameter_type.__name__}' for a number parameter." ) @@ -162,7 +189,7 @@ def _validate_choices( ensure_display_name(display_name) if not isinstance(value, parameter_type): raise ParameterDefinitionError( - f"All choices provided must match type {type(parameter_type)}" + f"All choices provided must be of type '{parameter_type.__name__}'" ) @@ -181,21 +208,27 @@ def _validate_min_and_max( "If a maximum value is provided a minimum must also be provided." ) elif maximum is not None and minimum is not None: - if isinstance(maximum, (int, float)) and isinstance(minimum, (int, float)): - if maximum <= minimum: + if parameter_type is int or parameter_type is float: + if not isinstance(minimum, parameter_type): raise ParameterDefinitionError( - "Maximum must be greater than the minimum" + f"Minimum is type '{type(minimum).__name__}'," + f" but must be of parameter type '{parameter_type.__name__}'" ) - - if not isinstance(minimum, parameter_type) or not isinstance( - maximum, parameter_type - ): + if not isinstance(maximum, parameter_type): raise ParameterDefinitionError( - f"Minimum and maximum must match type {parameter_type}" + f"Maximum is type '{type(maximum).__name__}'," + f" but must be of parameter type '{parameter_type.__name__}'" + ) + # These asserts are for the type checker and should never actually be asserted false + assert isinstance(minimum, (int, float)) + assert isinstance(maximum, (int, float)) + if maximum < minimum: + raise ParameterDefinitionError( + "Maximum must be greater than the minimum" ) else: raise ParameterDefinitionError( - "Only parameters of type float or int can have a minimum and maximum" + "Only parameters of type float or int can have a minimum and maximum." ) @@ -203,7 +236,8 @@ def validate_type(value: ParamType, parameter_type: type) -> None: """Validate parameter value is the correct type.""" if not isinstance(value, parameter_type): raise ParameterValueError( - f"Parameter value {value} has type {type(value)}, must match type {parameter_type}." + f"Parameter value {value} has type '{type(value).__name__}'," + f" but must be of type '{parameter_type.__name__}'." ) @@ -215,7 +249,11 @@ def validate_options( parameter_type: type, ) -> None: """Validate default values and all possible constraints for a valid parameter definition.""" - validate_type(default, parameter_type) + if not isinstance(default, parameter_type): + raise ParameterValueError( + f"Parameter default {default} has type '{type(default).__name__}'," + f" but must be of type '{parameter_type.__name__}'." + ) if choices is None and minimum is None and maximum is None: raise ParameterDefinitionError( diff --git a/api/src/opentrons/system/camera.py b/api/src/opentrons/system/camera.py index 1c2d09d8747..761a9ba66a1 100644 --- a/api/src/opentrons/system/camera.py +++ b/api/src/opentrons/system/camera.py @@ -1,6 +1,7 @@ import asyncio import os from pathlib import Path + from opentrons.config import ARCHITECTURE, SystemArchitecture from opentrons_shared_data.errors.exceptions import CommunicationError from opentrons_shared_data.errors.codes import ErrorCodes @@ -29,7 +30,7 @@ async def take_picture(filename: Path) -> None: pass if ARCHITECTURE == SystemArchitecture.YOCTO: - cmd = f"v4l2-ctl --device /dev/video0 --set-fmt-video=width=1280,height=720,pixelformat=MJPG --stream-mmap --stream-to={str(filename)} --stream-count=1" + cmd = f"v4l2-ctl --device /dev/video2 --set-fmt-video=width=1280,height=720,pixelformat=MJPG --stream-mmap --stream-to={str(filename)} --stream-count=1" elif ARCHITECTURE == SystemArchitecture.BUILDROOT: cmd = f"ffmpeg -f video4linux2 -s 640x480 -i /dev/video0 -ss 0:0:1 -frames 1 {str(filename)}" else: # HOST diff --git a/api/src/opentrons/util/change_notifier.py b/api/src/opentrons/util/change_notifier.py new file mode 100644 index 00000000000..e3ae1622c4c --- /dev/null +++ b/api/src/opentrons/util/change_notifier.py @@ -0,0 +1,47 @@ +"""Simple state change notification interface.""" +import asyncio + + +class ChangeNotifier: + """An interface to emit or subscribe to state change notifications.""" + + def __init__(self) -> None: + """Initialize the ChangeNotifier with an internal Event.""" + self._event = asyncio.Event() + + def notify(self) -> None: + """Notify all `wait`'ers that the state has changed.""" + self._event.set() + + async def wait(self) -> None: + """Wait until the next state change notification.""" + self._event.clear() + await self._event.wait() + + +class ChangeNotifier_ts(ChangeNotifier): + """ChangeNotifier initialized with Event_ts.""" + + def __init__(self) -> None: + """Initialize the ChangeNotifier_Ts with an internal Event_ts.""" + super().__init__() + self._event = Event_ts() + + +class Event_ts(asyncio.Event): + """asyncio.Event with threadsafe methods.""" + + def __init__(self) -> None: + """Initialize Event_ts with the active event_loop or event_loop_policy if not active.""" + super().__init__() + if self._loop is None: + self._loop: asyncio.AbstractEventLoop = asyncio.get_event_loop() + + def set(self) -> None: + """Primarily intended for calling from a thread not responsible for the event loop. + + Calling set() from the event loop thread will actually delay the execution of the set() until the + calling method either yields, awaits, or exits altogether. This is usually fine but might occasionally cause + unexpected behavior. + """ + self._loop.call_soon_threadsafe(super().set) diff --git a/api/src/opentrons/util/performance_helpers.py b/api/src/opentrons/util/performance_helpers.py new file mode 100644 index 00000000000..a157908303d --- /dev/null +++ b/api/src/opentrons/util/performance_helpers.py @@ -0,0 +1,76 @@ +"""Performance helpers for tracking robot context.""" + +from pathlib import Path +from opentrons_shared_data.performance.dev_types import ( + SupportsTracking, + F, + RobotContextState, +) +from opentrons_shared_data.robot.dev_types import RobotTypeEnum +from typing import Callable, Type +from opentrons.config import ( + feature_flags as ff, + get_performance_metrics_data_dir, + robot_configs, +) + + +_should_track = ff.enable_performance_metrics( + RobotTypeEnum.robot_literal_to_enum(robot_configs.load().model) +) + + +class StubbedTracker(SupportsTracking): + """A stubbed tracker that does nothing.""" + + def __init__(self, storage_location: Path, should_track: bool) -> None: + """Initialize the stubbed tracker.""" + pass + + def track(self, state: RobotContextState) -> Callable[[F], F]: + """Return the function unchanged.""" + + def inner_decorator(func: F) -> F: + """Return the function unchanged.""" + return func + + return inner_decorator + + def store(self) -> None: + """Do nothing.""" + pass + + +def _handle_package_import() -> Type[SupportsTracking]: + """Handle the import of the performance_metrics package. + + If the package is not available, return a stubbed tracker. + """ + try: + from performance_metrics import RobotContextTracker + + return RobotContextTracker + except ImportError: + return StubbedTracker + + +package_to_use = _handle_package_import() +_robot_context_tracker: SupportsTracking | None = None + + +def _get_robot_context_tracker() -> SupportsTracking: + """Singleton for the robot context tracker.""" + global _robot_context_tracker + if _robot_context_tracker is None: + # TODO: replace with path lookup and should_store lookup + _robot_context_tracker = package_to_use( + get_performance_metrics_data_dir(), _should_track + ) + return _robot_context_tracker + + +def track_analysis(func: F) -> F: + """Track the analysis of a protocol.""" + return _get_robot_context_tracker().track(RobotContextState.ANALYZING_PROTOCOL)( + func + ) diff --git a/api/tests/opentrons/calibration_storage/test_deck_configuration.py b/api/tests/opentrons/calibration_storage/test_deck_configuration.py index 3cb8d59535f..afdd4449eb4 100644 --- a/api/tests/opentrons/calibration_storage/test_deck_configuration.py +++ b/api/tests/opentrons/calibration_storage/test_deck_configuration.py @@ -10,8 +10,12 @@ def test_deck_configuration_serdes() -> None: """Test that deck configuration serialization/deserialization survives a round trip.""" dummy_cutout_fixture_placements = [ - CutoutFixturePlacement(cutout_fixture_id="a", cutout_id="b"), - CutoutFixturePlacement(cutout_fixture_id="c", cutout_id="d"), + CutoutFixturePlacement( + cutout_fixture_id="a", cutout_id="b", opentrons_module_serial_number="1" + ), + CutoutFixturePlacement( + cutout_fixture_id="c", cutout_id="d", opentrons_module_serial_number="2" + ), ] dummy_datetime = datetime(year=1961, month=5, day=6, tzinfo=timezone.utc) diff --git a/api/tests/opentrons/cli/test_cli.py b/api/tests/opentrons/cli/test_cli.py index eae5aa31ccc..818c4e9a1df 100644 --- a/api/tests/opentrons/cli/test_cli.py +++ b/api/tests/opentrons/cli/test_cli.py @@ -1,16 +1,42 @@ """Test cli execution.""" + + import json import tempfile import textwrap -from dataclasses import dataclass +from dataclasses import dataclass, replace from typing import Any, Dict, Iterator, List, Optional from pathlib import Path import pytest from click.testing import CliRunner +from opentrons_shared_data.performance.dev_types import ( + RobotContextState, +) +from opentrons.util.performance_helpers import _get_robot_context_tracker + + +# Enable tracking for the RobotContextTracker +# This must come before the import of the analyze CLI +context_tracker = _get_robot_context_tracker() + +# Ignore the type error for the next line, as we're setting a private attribute for testing purposes +context_tracker._should_track = True # type: ignore[attr-defined] + +from opentrons.cli.analyze import analyze # noqa: E402 + -from opentrons.cli.analyze import analyze +@pytest.fixture +def override_data_store(tmp_path: Path) -> Iterator[None]: + """Override the data store metadata for the RobotContextTracker.""" + old_store = context_tracker._store # type: ignore[attr-defined] + old_metadata = old_store.metadata + new_metadata = replace(old_metadata, storage_dir=tmp_path) + context_tracker._store = old_store.__class__(metadata=new_metadata) # type: ignore[attr-defined] + context_tracker._store.setup() # type: ignore[attr-defined] + yield + context_tracker._store = old_store # type: ignore[attr-defined] def _list_fixtures(version: int) -> Iterator[Path]: @@ -26,7 +52,9 @@ class _AnalysisCLIResult: stdout_stderr: str -def _get_analysis_result(protocol_files: List[Path]) -> _AnalysisCLIResult: +def _get_analysis_result( + protocol_files: List[Path], output_type: str, check: bool = False +) -> _AnalysisCLIResult: """Run `protocol_files` as a single protocol through the analysis CLI. Returns: @@ -38,14 +66,15 @@ def _get_analysis_result(protocol_files: List[Path]) -> _AnalysisCLIResult: with tempfile.TemporaryDirectory() as temp_dir: analysis_output_file = Path(temp_dir) / "analysis_output.json" runner = CliRunner() - result = runner.invoke( - analyze, - [ - "--json-output", - str(analysis_output_file), - *[str(p.resolve()) for p in protocol_files], - ], - ) + args = [ + output_type, + str(analysis_output_file), + *[str(p.resolve()) for p in protocol_files], + ] + if check: + args.append("--check") + + result = runner.invoke(analyze, args) if analysis_output_file.exists(): json_output = json.loads(analysis_output_file.read_bytes()) else: @@ -57,12 +86,14 @@ def _get_analysis_result(protocol_files: List[Path]) -> _AnalysisCLIResult: ) +@pytest.mark.parametrize("output", ["--json-output", "--human-json-output"]) @pytest.mark.parametrize("fixture_path", _list_fixtures(6)) def test_analyze( fixture_path: Path, + output: str, ) -> None: """Should return with no errors and a non-empty output.""" - result = _get_analysis_result([fixture_path]) + result = _get_analysis_result([fixture_path], output) assert result.exit_code == 0 @@ -98,6 +129,7 @@ def run(protocol): ) +@pytest.mark.parametrize("output", ["--json-output", "--human-json-output"]) @pytest.mark.parametrize( ("api_level", "robot_type", "expected_point"), [ @@ -119,6 +151,7 @@ def test_analysis_deck_definition( robot_type: str, expected_point: str, tmp_path: Path, + output: str, ) -> None: """Test that the analysis uses the appropriate deck definition for the protocol's robot type. @@ -135,7 +168,7 @@ def test_analysis_deck_definition( encoding="utf-8", ) - result = _get_analysis_result([protocol_source_file]) + result = _get_analysis_result([protocol_source_file], output) assert result.exit_code == 0 @@ -151,7 +184,8 @@ def test_analysis_deck_definition( # TODO(mm, 2023-08-12): We can remove this test when we remove special handling for these # protocols. https://opentrons.atlassian.net/browse/RSS-306 -def test_strict_metatada_requirements_validation(tmp_path: Path) -> None: +@pytest.mark.parametrize("output", ["--json-output", "--human-json-output"]) +def test_strict_metatada_requirements_validation(tmp_path: Path, output: str) -> None: """It should apply strict validation to the metadata and requirements dicts. It should reject protocols with questionable metadata and requirements dicts, @@ -172,7 +206,7 @@ def run(protocol): protocol_source_file = tmp_path / "protocol.py" protocol_source_file.write_text(protocol_source, encoding="utf-8") - result = _get_analysis_result([protocol_source_file]) + result = _get_analysis_result([protocol_source_file], output) assert result.exit_code != 0 @@ -182,6 +216,8 @@ def run(protocol): assert expected_message in result.stdout_stderr +@pytest.mark.parametrize("output", ["--json-output", "--human-json-output"]) +@pytest.mark.parametrize("check", [True, False]) @pytest.mark.parametrize( ("python_protocol_source", "expected_detail"), [ @@ -230,15 +266,60 @@ def run(protocol): # line 3 ], ) def test_python_error_line_numbers( - tmp_path: Path, python_protocol_source: str, expected_detail: str + tmp_path: Path, + python_protocol_source: str, + expected_detail: str, + output: str, + check: bool, ) -> None: """Test that error messages from Python protocols have line numbers.""" protocol_source_file = tmp_path / "protocol.py" protocol_source_file.write_text(python_protocol_source, encoding="utf-8") - result = _get_analysis_result([protocol_source_file]) + result = _get_analysis_result([protocol_source_file], output, check) - assert result.exit_code == 0 + if check: + assert result.exit_code != 0 + else: + assert result.exit_code == 0 assert result.json_output is not None [error] = result.json_output["errors"] assert error["detail"] == expected_detail + + +@pytest.mark.usefixtures("override_data_store") +@pytest.mark.parametrize("output", ["--json-output", "--human-json-output"]) +def test_track_analysis(tmp_path: Path, output: str) -> None: + """Test that the RobotContextTracker tracks analysis.""" + protocol_source = textwrap.dedent( + """ + requirements = {"apiLevel": "2.15"} + + def run(protocol): + pass + """ + ) + protocol_source_file = tmp_path / "protocol.py" + protocol_source_file.write_text(protocol_source, encoding="utf-8") + store = context_tracker._store # type: ignore[attr-defined] + + num_storage_entities_before_analysis = len(store._data) + + _get_analysis_result([protocol_source_file], output) + + assert len(store._data) == num_storage_entities_before_analysis + 1 + + with open(store.metadata.data_file_location, "r") as f: + stored_data = f.readlines() + assert len(stored_data) == 0 + + context_tracker.store() + + with open(store.metadata.data_file_location, "r") as f: + stored_data = f.readlines() + stored_data = [line.strip() for line in stored_data if line.strip()] + assert len(stored_data) == 1 + state_id, start_time, duration = stored_data[0].strip().split(",") + assert state_id == str(RobotContextState.ANALYZING_PROTOCOL.state_id) + assert start_time.isdigit() + assert duration.isdigit() diff --git a/api/tests/opentrons/config/ot3_settings.py b/api/tests/opentrons/config/ot3_settings.py index c5279c70818..690127b04b4 100644 --- a/api/tests/opentrons/config/ot3_settings.py +++ b/api/tests/opentrons/config/ot3_settings.py @@ -129,7 +129,7 @@ "aspirate_while_sensing": False, "auto_zero_sensor": True, "num_baseline_reads": 10, - "data_file": "/var/pressure_sensor_data.csv", + "data_files": {"PRIMARY": "/data/pressure_sensor_data.csv"}, }, "calibration": { "z_offset": { diff --git a/api/tests/opentrons/config/test_advanced_settings_migration.py b/api/tests/opentrons/config/test_advanced_settings_migration.py index e3269433db5..283d11a3000 100644 --- a/api/tests/opentrons/config/test_advanced_settings_migration.py +++ b/api/tests/opentrons/config/test_advanced_settings_migration.py @@ -8,7 +8,7 @@ @pytest.fixture def migrated_file_version() -> int: - return 33 + return 34 # make sure to set a boolean value in default_file_settings only if @@ -22,7 +22,6 @@ def default_file_settings() -> Dict[str, Any]: "useOldAspirationFunctions": None, "disableLogAggregation": None, "enableDoorSafetySwitch": None, - "disableFastProtocolUpload": None, "enableOT3HardwareController": None, "rearPanelIntegration": True, "disableStallDetection": None, @@ -405,6 +404,14 @@ def v33_config(v32_config: Dict[str, Any]) -> Dict[str, Any]: return r +@pytest.fixture +def v34_config(v33_config: Dict[str, Any]) -> Dict[str, Any]: + r = v33_config.copy() + r.pop("disableFastProtocolUpload") + r["_version"] = 34 + return r + + @pytest.fixture( scope="session", params=[ @@ -443,6 +450,7 @@ def v33_config(v32_config: Dict[str, Any]) -> Dict[str, Any]: lazy_fixture("v31_config"), lazy_fixture("v32_config"), lazy_fixture("v33_config"), + lazy_fixture("v34_config"), ], ) def old_settings(request: SubRequest) -> Dict[str, Any]: @@ -527,7 +535,6 @@ def test_ensures_config() -> None: "useOldAspirationFunctions": None, "disableLogAggregation": True, "enableDoorSafetySwitch": None, - "disableFastProtocolUpload": None, "enableOT3HardwareController": None, "rearPanelIntegration": None, "disableStallDetection": None, diff --git a/api/tests/opentrons/conftest.py b/api/tests/opentrons/conftest.py index dcf6b6c4e37..de731268bce 100755 --- a/api/tests/opentrons/conftest.py +++ b/api/tests/opentrons/conftest.py @@ -40,7 +40,7 @@ from opentrons_shared_data.deck.dev_types import ( RobotModel, DeckDefinitionV3, - DeckDefinitionV4, + DeckDefinitionV5, ) from opentrons_shared_data.deck import ( load as load_deck, @@ -256,7 +256,7 @@ def deck_definition_name(robot_model: RobotModel) -> str: @pytest.fixture -def deck_definition(deck_definition_name: str) -> DeckDefinitionV4: +def deck_definition(deck_definition_name: str) -> DeckDefinitionV5: return load_deck(deck_definition_name, DEFAULT_DECK_DEFINITION_VERSION) diff --git a/api/tests/opentrons/hardware_control/backends/test_ot3_controller.py b/api/tests/opentrons/hardware_control/backends/test_ot3_controller.py index 12743993d33..ed639444b3d 100644 --- a/api/tests/opentrons/hardware_control/backends/test_ot3_controller.py +++ b/api/tests/opentrons/hardware_control/backends/test_ot3_controller.py @@ -61,6 +61,7 @@ UpdateState, EstopState, CurrentConfig, + InstrumentProbeType, ) from opentrons.hardware_control.errors import ( InvalidPipetteName, @@ -185,7 +186,7 @@ def fake_liquid_settings() -> LiquidProbeSettings: aspirate_while_sensing=False, auto_zero_sensor=False, num_baseline_reads=8, - data_file="fake_data_file", + data_files={InstrumentProbeType.PRIMARY: "fake_file_name"}, ) diff --git a/api/tests/opentrons/hardware_control/backends/test_ot3_tip_presence_manager.py b/api/tests/opentrons/hardware_control/backends/test_ot3_tip_presence_manager.py index 543f7b3b400..6ea39738fc2 100644 --- a/api/tests/opentrons/hardware_control/backends/test_ot3_tip_presence_manager.py +++ b/api/tests/opentrons/hardware_control/backends/test_ot3_tip_presence_manager.py @@ -2,7 +2,7 @@ from typing import AsyncIterator, Dict from decoy import Decoy -from opentrons.hardware_control.types import OT3Mount, TipStateType +from opentrons.hardware_control.types import OT3Mount, TipStateType, InstrumentProbeType from opentrons.hardware_control.backends.tip_presence_manager import TipPresenceManager from opentrons_hardware.hardware_control.tip_presence import ( TipDetector, @@ -110,6 +110,51 @@ async def test_get_tip_status_for_high_throughput( result == expected_type +@pytest.mark.parametrize( + "tip_presence,expected_type,sensor_to_look_at", + [ + ( + {SensorId.S0: False, SensorId.S1: False}, + TipStateType.ABSENT, + InstrumentProbeType.PRIMARY, + ), + ( + {SensorId.S0: True, SensorId.S1: True}, + TipStateType.PRESENT, + InstrumentProbeType.SECONDARY, + ), + ( + {SensorId.S0: False, SensorId.S1: True}, + TipStateType.ABSENT, + InstrumentProbeType.PRIMARY, + ), + ( + {SensorId.S0: False, SensorId.S1: True}, + TipStateType.PRESENT, + InstrumentProbeType.SECONDARY, + ), + ], +) +async def test_allow_different_tip_states_ht( + subject: TipPresenceManager, + tip_detector_controller: TipDetectorController, + tip_presence: Dict[SensorId, bool], + expected_type: TipStateType, + sensor_to_look_at: InstrumentProbeType, +) -> None: + mount = OT3Mount.LEFT + await tip_detector_controller.retrieve_tip_status_highthroughput(tip_presence) + + result = await subject.get_tip_status(mount, sensor_to_look_at) + result == expected_type + + # if sensor_to_look_at is not used, different tip states + # should result in an UnmatchedTipStates error + if len(set(tip_presence[t] for t in tip_presence)) > 1: + with pytest.raises(UnmatchedTipPresenceStates): + result = await subject.get_tip_status(mount) + + @pytest.mark.parametrize( "tip_presence", [ diff --git a/api/tests/opentrons/hardware_control/instruments/test_nozzle_manager.py b/api/tests/opentrons/hardware_control/instruments/test_nozzle_manager.py index dc06ce9ea62..bd521a6e8a2 100644 --- a/api/tests/opentrons/hardware_control/instruments/test_nozzle_manager.py +++ b/api/tests/opentrons/hardware_control/instruments/test_nozzle_manager.py @@ -414,7 +414,7 @@ def test_96_config_identification( ) == nozzle_manager.NozzleConfigurationType.SUBRECT ) - subject.update_nozzle_configuration("A1", "D12") + subject.update_nozzle_configuration("A1", "B12") assert ( cast( nozzle_manager.NozzleConfigurationType, @@ -422,7 +422,7 @@ def test_96_config_identification( ) == nozzle_manager.NozzleConfigurationType.SUBRECT ) - subject.update_nozzle_configuration("E1", "H12") + subject.update_nozzle_configuration("G1", "H12") assert ( cast( nozzle_manager.NozzleConfigurationType, @@ -430,7 +430,7 @@ def test_96_config_identification( ) == nozzle_manager.NozzleConfigurationType.SUBRECT ) - subject.update_nozzle_configuration("A1", "H6") + subject.update_nozzle_configuration("A1", "H3") assert ( cast( nozzle_manager.NozzleConfigurationType, @@ -438,7 +438,7 @@ def test_96_config_identification( ) == nozzle_manager.NozzleConfigurationType.SUBRECT ) - subject.update_nozzle_configuration("A7", "H12") + subject.update_nozzle_configuration("A10", "H12") assert ( cast( nozzle_manager.NozzleConfigurationType, diff --git a/api/tests/opentrons/hardware_control/test_gripper.py b/api/tests/opentrons/hardware_control/test_gripper.py index 0d01b225752..6066b8a74a1 100644 --- a/api/tests/opentrons/hardware_control/test_gripper.py +++ b/api/tests/opentrons/hardware_control/test_gripper.py @@ -74,6 +74,7 @@ def test_reload_instrument_cal_ot3(fake_offset: "GripperCalibrationOffset") -> N fake_gripper_conf, fake_offset, "fakeid123", + jaw_max_offset=15, ) # if only calibration is changed new_cal = instrument_calibration.GripperCalibrationOffset( @@ -87,10 +88,37 @@ def test_reload_instrument_cal_ot3(fake_offset: "GripperCalibrationOffset") -> N # it's the same gripper assert new_gripper == old_gripper + # jaw offset should persists as well + assert new_gripper._jaw_max_offset == old_gripper._jaw_max_offset # we said upstream could skip assert skip +@pytest.mark.ot3_only +def test_reload_instrument_cal_ot3_conf_changed( + fake_offset: "GripperCalibrationOffset", +) -> None: + old_gripper = gripper.Gripper( + fake_gripper_conf, + fake_offset, + "fakeid123", + jaw_max_offset=15, + ) + new_conf = fake_gripper_conf.copy( + update={"grip_force_profile": {"default_grip_force": 1}} + ) + assert new_conf != old_gripper.config + + new_gripper, skip = gripper._reload_gripper(new_conf, old_gripper, fake_offset) + + # it's not the same gripper + assert new_gripper != old_gripper + # do not pass in the old jaw max offse + assert not new_gripper._jaw_max_offset + # we said upstream could skip + assert not skip + + @pytest.mark.ot3_only def test_jaw_calibration_error_checking() -> None: subject = gripper.Gripper(fake_gripper_conf, fake_offset, "fakeid123") diff --git a/api/tests/opentrons/hardware_control/test_instruments.py b/api/tests/opentrons/hardware_control/test_instruments.py index 7db8a5303ee..d3907451717 100644 --- a/api/tests/opentrons/hardware_control/test_instruments.py +++ b/api/tests/opentrons/hardware_control/test_instruments.py @@ -263,7 +263,7 @@ def fake_func2(mount, value): {types.Mount.LEFT: "p10_single", types.Mount.RIGHT: "p300_single_gen2"} ) attached = sim.attached_instruments - assert attached[types.Mount.LEFT]["model"] == "p10_single_v1" + assert attached[types.Mount.LEFT]["model"] == "p10_single_v1.5" assert attached[types.Mount.LEFT]["name"] == "p10_single" steps_mm_calls = [mock.call({"B": 768}), mock.call({"C": 3200})] @@ -291,7 +291,7 @@ def fake_func2(mount, value): # If we use prefixes, that should work too await sim.cache_instruments({types.Mount.RIGHT: "p300_single"}) attached = sim.attached_instruments - assert attached[types.Mount.RIGHT]["model"] == "p300_single_v1" + assert attached[types.Mount.RIGHT]["model"] == "p300_single_v1.5" assert attached[types.Mount.RIGHT]["name"] == "p300_single" # If we specify instruments at init time, we should get them without # passing an expectation diff --git a/api/tests/opentrons/hardware_control/test_ot3_api.py b/api/tests/opentrons/hardware_control/test_ot3_api.py index b9af5eb5146..ebb82116b65 100644 --- a/api/tests/opentrons/hardware_control/test_ot3_api.py +++ b/api/tests/opentrons/hardware_control/test_ot3_api.py @@ -126,7 +126,7 @@ def fake_liquid_settings() -> LiquidProbeSettings: aspirate_while_sensing=False, auto_zero_sensor=False, num_baseline_reads=10, - data_file="fake_file_name", + data_files={InstrumentProbeType.PRIMARY: "fake_file_name"}, ) @@ -813,7 +813,7 @@ async def test_liquid_probe( aspirate_while_sensing=True, auto_zero_sensor=False, num_baseline_reads=10, - data_file="fake_file_name", + data_files={InstrumentProbeType.PRIMARY: "fake_file_name"}, ) await ot3_hardware.liquid_probe(mount, fake_settings_aspirate) mock_move_to_plunger_bottom.assert_called_once() @@ -824,7 +824,7 @@ async def test_liquid_probe( (fake_settings_aspirate.plunger_speed * -1), fake_settings_aspirate.sensor_threshold_pascals, fake_settings_aspirate.output_option, - fake_settings_aspirate.data_file, + fake_settings_aspirate.data_files, fake_settings_aspirate.auto_zero_sensor, fake_settings_aspirate.num_baseline_reads, probe=InstrumentProbeType.PRIMARY, diff --git a/api/tests/opentrons/protocol_api/__init__.py b/api/tests/opentrons/protocol_api/__init__.py index 70938f49e66..8cf95c55e6d 100644 --- a/api/tests/opentrons/protocol_api/__init__.py +++ b/api/tests/opentrons/protocol_api/__init__.py @@ -1 +1,131 @@ """Tests for opentrons.protocol_api.""" +from typing import List, overload, Optional + +from opentrons.protocols.api_support.types import APIVersion +from opentrons.protocol_api import ( + MAX_SUPPORTED_VERSION, + MIN_SUPPORTED_VERSION, + MIN_SUPPORTED_VERSION_FOR_FLEX, +) + + +def versions_at_or_above(from_version: APIVersion) -> List[APIVersion]: + """Get a list of versions >= the specified one.""" + return versions_between( + low_inclusive_bound=from_version, high_inclusive_bound=MAX_SUPPORTED_VERSION + ) + + +def versions_at_or_below( + from_version: APIVersion, flex_only: bool = False +) -> List[APIVersion]: + """Get a list of versions <= the specified one. + + Since there are different minimum supported versions for Flex and OT-2, specify which you care about + with the second argument. + """ + if flex_only: + return versions_between( + low_inclusive_bound=MIN_SUPPORTED_VERSION_FOR_FLEX, + high_inclusive_bound=from_version, + ) + else: + return versions_between( + low_inclusive_bound=MIN_SUPPORTED_VERSION, high_inclusive_bound=from_version + ) + + +def versions_above(from_version: APIVersion) -> List[APIVersion]: + """Get a list of versions > the specified one.""" + return versions_between( + low_exclusive_bound=from_version, high_inclusive_bound=MAX_SUPPORTED_VERSION + ) + + +def versions_below(from_version: APIVersion, flex_only: bool) -> List[APIVersion]: + """Get a list of versions < the specified one. + + Since there are different minimum supported versions for Flex and OT-2, specify which you care about + with the second argument. + """ + if flex_only: + return versions_between( + low_inclusive_bound=MIN_SUPPORTED_VERSION_FOR_FLEX, + high_exclusive_bound=from_version, + ) + else: + return versions_between( + low_inclusive_bound=MIN_SUPPORTED_VERSION, high_exclusive_bound=from_version + ) + + +@overload +def versions_between( + *, + low_inclusive_bound: APIVersion, + high_inclusive_bound: APIVersion, +) -> List[APIVersion]: + ... + + +@overload +def versions_between( + *, low_inclusive_bound: APIVersion, high_exclusive_bound: APIVersion +) -> List[APIVersion]: + ... + + +@overload +def versions_between( + *, + high_inclusive_bound: APIVersion, + low_exclusive_bound: APIVersion, +) -> List[APIVersion]: + ... + + +@overload +def versions_between( + *, low_exclusive_bound: APIVersion, high_exclusive_bound: APIVersion +) -> List[APIVersion]: + ... + + +def versions_between( + low_inclusive_bound: Optional[APIVersion] = None, + high_inclusive_bound: Optional[APIVersion] = None, + low_exclusive_bound: Optional[APIVersion] = None, + high_exclusive_bound: Optional[APIVersion] = None, +) -> List[APIVersion]: + """Build a list of versions based on exclusive and inclusive constraints.""" + if low_inclusive_bound and high_inclusive_bound: + assert ( + low_inclusive_bound.major == high_inclusive_bound.major + ), "You need to change this test when you add a new major version" + major = low_inclusive_bound.major + start = low_inclusive_bound.minor + stop = high_inclusive_bound.minor + 1 + elif low_inclusive_bound and high_exclusive_bound: + assert ( + low_inclusive_bound.major == high_exclusive_bound.major + ), "You need to change this test when you add a new major version" + major = low_inclusive_bound.major + start = low_inclusive_bound.minor + stop = high_exclusive_bound.minor + elif low_exclusive_bound and high_inclusive_bound: + assert ( + low_exclusive_bound.major == high_inclusive_bound.major + ), "You need to change this test when you add a new major version" + major = low_exclusive_bound.major + start = low_exclusive_bound.minor + 1 + stop = high_inclusive_bound.minor + 1 + elif low_exclusive_bound and high_exclusive_bound: + assert ( + low_exclusive_bound.major == high_exclusive_bound.major + ), "You need to change this test when you add a new major version" + major = low_exclusive_bound.major + start = low_exclusive_bound.minor + 1 + stop = high_exclusive_bound.minor + else: + raise ValueError("You must specify one low bound and one high bound") + return [APIVersion(major, minor) for minor in range(start, stop)] diff --git a/api/tests/opentrons/protocol_api/core/engine/test_labware_core.py b/api/tests/opentrons/protocol_api/core/engine/test_labware_core.py index 37d4511cce0..e02b5e7b8f7 100644 --- a/api/tests/opentrons/protocol_api/core/engine/test_labware_core.py +++ b/api/tests/opentrons/protocol_api/core/engine/test_labware_core.py @@ -19,9 +19,15 @@ from opentrons.types import DeckSlotName, Point from opentrons.protocol_engine.clients import SyncClient as EngineClient from opentrons.protocol_engine.errors import LabwareNotOnDeckError +from opentrons.protocol_engine.types import ( + LabwareOffsetCreate, + LabwareOffsetLocation, + LabwareOffsetVector, +) from opentrons.protocol_api.core.labware import LabwareLoadParams from opentrons.protocol_api.core.engine import LabwareCore, WellCore +from opentrons.calibration_storage.helpers import uri_from_details @pytest.fixture @@ -36,11 +42,9 @@ def mock_engine_client( ) -> EngineClient: """Get a mock ProtocolEngine synchronous client.""" engine_client = decoy.mock(cls=EngineClient) - decoy.when(engine_client.state.labware.get_definition("cool-labware")).then_return( labware_definition ) - return engine_client @@ -67,9 +71,87 @@ def test_get_load_params(subject: LabwareCore) -> None: assert subject.load_name == "world" -def test_set_calibration(subject: LabwareCore) -> None: - """It should raise if you attempt to set calibration.""" - with pytest.raises(NotImplementedError): +@pytest.mark.parametrize( + "labware_definition", + [ + LabwareDefinition.construct( # type: ignore[call-arg] + namespace="hello", + version=42, + parameters=LabwareDefinitionParameters.construct(loadName="world"), # type: ignore[call-arg] + ordering=[], + metadata=LabwareDefinitionMetadata.construct(displayName="what a cool labware"), # type: ignore[call-arg] + ) + ], +) +def test_set_calibration_succeeds_in_ok_location( + decoy: Decoy, + subject: LabwareCore, + mock_engine_client: EngineClient, + labware_definition: LabwareDefinition, +) -> None: + """It should pass along an AddLabwareOffset if possible.""" + decoy.when( + mock_engine_client.state.labware.get_definition_uri("cool-labware") + ).then_return( + uri_from_details( + load_name=labware_definition.parameters.loadName, + namespace=labware_definition.namespace, + version=labware_definition.version, + ) + ) + decoy.when( + mock_engine_client.state.labware.get_display_name("cool-labware") + ).then_return("what a cool labware") + location = LabwareOffsetLocation(slotName=DeckSlotName.SLOT_C2) + decoy.when( + mock_engine_client.state.geometry.get_offset_location("cool-labware") + ).then_return(location) + subject.set_calibration(Point(1, 2, 3)) + decoy.verify( + mock_engine_client.add_labware_offset( + LabwareOffsetCreate( + definitionUri="hello/world/42", + location=location, + vector=LabwareOffsetVector(x=1, y=2, z=3), + ) + ), + mock_engine_client.reload_labware( + labware_id="cool-labware", + ), + ) + + +@pytest.mark.parametrize( + "labware_definition", + [ + LabwareDefinition.construct( # type: ignore[call-arg] + namespace="hello", + version=42, + parameters=LabwareDefinitionParameters.construct(loadName="world"), # type: ignore[call-arg] + ordering=[], + ) + ], +) +def test_set_calibration_fails_in_bad_location( + decoy: Decoy, + subject: LabwareCore, + mock_engine_client: EngineClient, + labware_definition: LabwareDefinition, +) -> None: + """It should raise if you attempt to set calibration when the labware is not on deck.""" + decoy.when( + mock_engine_client.state.labware.get_definition_uri("cool-labware") + ).then_return( + uri_from_details( + load_name=labware_definition.parameters.loadName, + namespace=labware_definition.namespace, + version=labware_definition.version, + ) + ) + decoy.when( + mock_engine_client.state.geometry.get_offset_location("cool-labware") + ).then_return(None) + with pytest.raises(LabwareNotOnDeckError): subject.set_calibration(Point(1, 2, 3)) diff --git a/api/tests/opentrons/protocol_api/core/engine/test_protocol_core.py b/api/tests/opentrons/protocol_api/core/engine/test_protocol_core.py index fdf12f1e51b..8f6589b1104 100644 --- a/api/tests/opentrons/protocol_api/core/engine/test_protocol_core.py +++ b/api/tests/opentrons/protocol_api/core/engine/test_protocol_core.py @@ -7,7 +7,10 @@ from decoy import Decoy from opentrons_shared_data.deck import load as load_deck -from opentrons_shared_data.deck.dev_types import DeckDefinitionV4, SlotDefV3 +from opentrons_shared_data.deck.dev_types import ( + DeckDefinitionV5, + SlotDefV3, +) from opentrons_shared_data.pipette.dev_types import PipetteNameType from opentrons_shared_data.labware.dev_types import ( LabwareDefinition as LabwareDefDict, @@ -85,15 +88,15 @@ @pytest.fixture(scope="session") -def ot2_standard_deck_def() -> DeckDefinitionV4: +def ot2_standard_deck_def() -> DeckDefinitionV5: """Get the OT-2 standard deck definition.""" - return load_deck(STANDARD_OT2_DECK, 4) + return load_deck(STANDARD_OT2_DECK, 5) @pytest.fixture(scope="session") -def ot3_standard_deck_def() -> DeckDefinitionV4: +def ot3_standard_deck_def() -> DeckDefinitionV5: """Get the OT-2 standard deck definition.""" - return load_deck(STANDARD_OT3_DECK, 4) + return load_deck(STANDARD_OT3_DECK, 5) @pytest.fixture(autouse=True) @@ -180,7 +183,7 @@ def test_api_version( def test_get_slot_definition( - ot2_standard_deck_def: DeckDefinitionV4, subject: ProtocolCore, decoy: Decoy + ot2_standard_deck_def: DeckDefinitionV5, subject: ProtocolCore, decoy: Decoy ) -> None: """It should return a deck slot's definition.""" expected_slot_def = cast( @@ -1154,7 +1157,7 @@ def test_add_labware_definition( EngineModuleModel.THERMOCYCLER_MODULE_V2, ThermocyclerModuleCore, lazy_fixture("ot3_standard_deck_def"), - DeckSlotName.SLOT_A1, + DeckSlotName.SLOT_B1, "OT-3 Standard", ), ( @@ -1177,7 +1180,7 @@ def test_load_module( engine_model: EngineModuleModel, expected_core_cls: Type[ModuleCore], subject: ProtocolCore, - deck_def: DeckDefinitionV4, + deck_def: DeckDefinitionV5, slot_name: DeckSlotName, robot_type: RobotType, ) -> None: @@ -1193,12 +1196,22 @@ def test_load_module( [mock_hw_mod_1, mock_hw_mod_2] ) - decoy.when(subject.get_slot_definition(slot_name)).then_return( - cast( - SlotDefV3, - {"compatibleModuleTypes": [ModuleType.from_model(requested_model)]}, + if robot_type == "OT-2 Standard": + decoy.when(subject.get_slot_definition(slot_name)).then_return( + cast( + SlotDefV3, + {"compatibleModuleTypes": [ModuleType.from_model(requested_model)]}, + ) ) - ) + else: + decoy.when( + mock_engine_client.state.addressable_areas.state.deck_definition + ).then_return(deck_def) + decoy.when( + mock_engine_client.state.addressable_areas.get_cutout_id_by_deck_slot_name( + slot_name + ) + ).then_return("cutout" + slot_name.value) decoy.when(mock_engine_client.state.config.robot_type).then_return(robot_type) @@ -1251,97 +1264,6 @@ def test_load_module( assert subject.get_labware_on_module(result) is None -@pytest.mark.parametrize( - ( - "requested_model", - "engine_model", - "expected_core_cls", - "deck_def", - "slot_name", - "robot_type", - ), - [ - ( - TemperatureModuleModel.TEMPERATURE_V2, - EngineModuleModel.TEMPERATURE_MODULE_V2, - TemperatureModuleCore, - lazy_fixture("ot3_standard_deck_def"), - DeckSlotName.SLOT_D2, - "OT-3 Standard", - ), - ( - MagneticModuleModel.MAGNETIC_V2, - EngineModuleModel.MAGNETIC_MODULE_V2, - MagneticModuleCore, - lazy_fixture("ot3_standard_deck_def"), - DeckSlotName.SLOT_A2, - "OT-3 Standard", - ), - ( - ThermocyclerModuleModel.THERMOCYCLER_V1, - EngineModuleModel.THERMOCYCLER_MODULE_V1, - ThermocyclerModuleCore, - lazy_fixture("ot2_standard_deck_def"), - DeckSlotName.SLOT_1, - "OT-2 Standard", - ), - ( - ThermocyclerModuleModel.THERMOCYCLER_V2, - EngineModuleModel.THERMOCYCLER_MODULE_V2, - ThermocyclerModuleCore, - lazy_fixture("ot3_standard_deck_def"), - DeckSlotName.SLOT_A2, - "OT-3 Standard", - ), - ( - HeaterShakerModuleModel.HEATER_SHAKER_V1, - EngineModuleModel.HEATER_SHAKER_MODULE_V1, - HeaterShakerModuleCore, - lazy_fixture("ot3_standard_deck_def"), - DeckSlotName.SLOT_A2, - "OT-3 Standard", - ), - ], -) -def test_load_module_raises_wrong_location( - decoy: Decoy, - mock_engine_client: EngineClient, - mock_sync_hardware_api: SyncHardwareAPI, - requested_model: ModuleModel, - engine_model: EngineModuleModel, - expected_core_cls: Type[ModuleCore], - subject: ProtocolCore, - deck_def: DeckDefinitionV4, - slot_name: DeckSlotName, - robot_type: RobotType, -) -> None: - """It should issue a load module engine command.""" - mock_hw_mod_1 = decoy.mock(cls=AbstractModule) - mock_hw_mod_2 = decoy.mock(cls=AbstractModule) - - decoy.when(mock_hw_mod_1.device_info).then_return({"serial": "abc123"}) - decoy.when(mock_hw_mod_2.device_info).then_return({"serial": "xyz789"}) - decoy.when(mock_sync_hardware_api.attached_modules).then_return( - [mock_hw_mod_1, mock_hw_mod_2] - ) - - decoy.when(mock_engine_client.state.config.robot_type).then_return(robot_type) - - decoy.when(subject.get_slot_definition(slot_name)).then_return( - cast(SlotDefV3, {"compatibleModuleTypes": []}) - ) - - with pytest.raises( - ValueError, - match=f"A {ModuleType.from_model(requested_model).value} cannot be loaded into slot {slot_name}", - ): - subject.load_module( - model=requested_model, - deck_slot=slot_name, - configuration=None, - ) - - # APIv2.15 because we're expecting a fixed trash. @pytest.mark.parametrize("api_version", [APIVersion(2, 15)]) def test_load_mag_block( @@ -1349,7 +1271,7 @@ def test_load_mag_block( mock_engine_client: EngineClient, mock_sync_hardware_api: SyncHardwareAPI, subject: ProtocolCore, - ot3_standard_deck_def: DeckDefinitionV4, + ot3_standard_deck_def: DeckDefinitionV5, ) -> None: """It should issue a load module engine command.""" definition = ModuleDefinition.construct() # type: ignore[call-arg] @@ -1366,6 +1288,14 @@ def test_load_mag_block( }, ) ) + decoy.when( + mock_engine_client.state.addressable_areas.state.deck_definition + ).then_return(ot3_standard_deck_def) + decoy.when( + mock_engine_client.state.addressable_areas.get_cutout_id_by_deck_slot_name( + DeckSlotName.SLOT_A2 + ) + ).then_return("cutout" + DeckSlotName.SLOT_A2.value) decoy.when( mock_engine_client.load_module( @@ -1440,7 +1370,7 @@ def test_load_module_thermocycler_with_no_location( requested_model: ModuleModel, engine_model: EngineModuleModel, subject: ProtocolCore, - deck_def: DeckDefinitionV4, + deck_def: DeckDefinitionV5, expected_slot: DeckSlotName, ) -> None: """It should issue a load module engine command with location at 7.""" @@ -1450,12 +1380,14 @@ def test_load_module_thermocycler_with_no_location( decoy.when(mock_hw_mod.device_info).then_return({"serial": "xyz789"}) decoy.when(mock_sync_hardware_api.attached_modules).then_return([mock_hw_mod]) decoy.when(mock_engine_client.state.config.robot_type).then_return("OT-3 Standard") - decoy.when(subject.get_slot_definition(expected_slot)).then_return( - cast( - SlotDefV3, - {"compatibleModuleTypes": [ModuleType.from_model(requested_model)]}, + decoy.when( + mock_engine_client.state.addressable_areas.state.deck_definition + ).then_return(deck_def) + decoy.when( + mock_engine_client.state.addressable_areas.get_cutout_id_by_deck_slot_name( + expected_slot ) - ) + ).then_return("cutout" + expected_slot.value) decoy.when( mock_engine_client.load_module( @@ -1590,7 +1522,7 @@ def test_get_deck_definition( decoy: Decoy, mock_engine_client: EngineClient, subject: ProtocolCore ) -> None: """It should return the loaded deck definition from engine state.""" - deck_definition = cast(DeckDefinitionV4, {"schemaVersion": "4"}) + deck_definition = cast(DeckDefinitionV5, {"schemaVersion": "5"}) decoy.when(mock_engine_client.state.labware.get_deck_definition()).then_return( deck_definition diff --git a/api/tests/opentrons/protocol_api/test_deck.py b/api/tests/opentrons/protocol_api/test_deck.py index b3dc4716449..f471cb936e1 100644 --- a/api/tests/opentrons/protocol_api/test_deck.py +++ b/api/tests/opentrons/protocol_api/test_deck.py @@ -5,7 +5,7 @@ import pytest from decoy import Decoy -from opentrons_shared_data.deck.dev_types import DeckDefinitionV4, SlotDefV3 +from opentrons_shared_data.deck.dev_types import DeckDefinitionV5, SlotDefV3 from opentrons.motion_planning import adjacent_slots_getters as mock_adjacent_slots from opentrons.protocols.api_support.types import APIVersion @@ -23,10 +23,10 @@ @pytest.fixture -def deck_definition() -> DeckDefinitionV4: +def deck_definition() -> DeckDefinitionV5: """Get a deck definition value object.""" return cast( - DeckDefinitionV4, + DeckDefinitionV5, { "locations": {"addressableAreas": [], "calibrationPoints": []}, "cutoutFixtures": {}, @@ -81,7 +81,7 @@ def staging_slot_definitions_by_name() -> Dict[str, SlotDefV3]: @pytest.fixture def subject( decoy: Decoy, - deck_definition: DeckDefinitionV4, + deck_definition: DeckDefinitionV5, mock_protocol_core: ProtocolCore, mock_core_map: LoadedCoreMap, api_version: APIVersion, diff --git a/api/tests/opentrons/protocol_api/test_instrument_context.py b/api/tests/opentrons/protocol_api/test_instrument_context.py index 38ab8f5b54b..d0e18f6fda9 100644 --- a/api/tests/opentrons/protocol_api/test_instrument_context.py +++ b/api/tests/opentrons/protocol_api/test_instrument_context.py @@ -753,9 +753,14 @@ def test_drop_tip_to_randomized_trash_location( ) +@pytest.mark.parametrize( + ["api_version", "alternate_drop"], + [(APIVersion(2, 17), True), (APIVersion(2, 18), False)], +) def test_drop_tip_in_trash_bin( decoy: Decoy, mock_instrument_core: InstrumentCore, + alternate_drop: bool, subject: InstrumentContext, ) -> None: """It should drop a tip in a deck configured trash bin.""" @@ -767,14 +772,20 @@ def test_drop_tip_in_trash_bin( mock_instrument_core.drop_tip_in_disposal_location( trash_bin, home_after=None, + alternate_tip_drop=alternate_drop, ), times=1, ) +@pytest.mark.parametrize( + ["api_version", "alternate_drop"], + [(APIVersion(2, 17), True), (APIVersion(2, 18), False)], +) def test_drop_tip_in_waste_chute( decoy: Decoy, mock_instrument_core: InstrumentCore, + alternate_drop: bool, subject: InstrumentContext, ) -> None: """It should drop a tip in a deck configured trash bin or waste chute.""" @@ -786,6 +797,7 @@ def test_drop_tip_in_waste_chute( mock_instrument_core.drop_tip_in_disposal_location( waste_chute, home_after=None, + alternate_tip_drop=alternate_drop, ), times=1, ) diff --git a/api/tests/opentrons/protocol_api/test_labware.py b/api/tests/opentrons/protocol_api/test_labware.py index 58bb3ca0b0d..b9b008e77a1 100644 --- a/api/tests/opentrons/protocol_api/test_labware.py +++ b/api/tests/opentrons/protocol_api/test_labware.py @@ -24,6 +24,8 @@ from opentrons.types import Point +from . import versions_at_or_below, versions_at_or_above, versions_between + @pytest.fixture(autouse=True) def _mock_well_grid_module(decoy: Decoy, monkeypatch: pytest.MonkeyPatch) -> None: @@ -317,7 +319,7 @@ def test_child( assert subject.child == mock_labware -@pytest.mark.parametrize("api_version", [APIVersion(2, 13)]) +@pytest.mark.parametrize("api_version", versions_at_or_below(APIVersion(2, 13))) def test_set_offset_succeeds_on_low_api_version( decoy: Decoy, subject: Labware, @@ -328,8 +330,13 @@ def test_set_offset_succeeds_on_low_api_version( decoy.verify(mock_labware_core.set_calibration(Point(1, 2, 3))) -@pytest.mark.parametrize("api_version", [APIVersion(2, 14)]) -def test_set_offset_raises_on_high_api_version( +@pytest.mark.parametrize( + "api_version", + versions_between( + low_inclusive_bound=APIVersion(2, 14), high_inclusive_bound=APIVersion(2, 17) + ), +) +def test_set_offset_raises_on_intermediate_api_version( decoy: Decoy, subject: Labware, mock_labware_core: LabwareCore, @@ -339,7 +346,16 @@ def test_set_offset_raises_on_high_api_version( subject.set_offset(1, 2, 3) -@pytest.mark.parametrize("api_version", [APIVersion(2, 14)]) +@pytest.mark.parametrize("api_version", versions_at_or_above(APIVersion(2, 18))) +def test_set_offset_succeeds_on_high_api_version( + decoy: Decoy, subject: Labware, mock_labware_core: LabwareCore +) -> None: + """It should not raise an API version error on the most recent versions.""" + subject.set_offset(1, 2, 3) + decoy.verify(mock_labware_core.set_calibration(Point(1, 2, 3))) + + +@pytest.mark.parametrize("api_version", versions_at_or_above(APIVersion(2, 14))) def test_separate_calibration_raises_on_high_api_version( decoy: Decoy, subject: Labware, diff --git a/api/tests/opentrons/protocol_api/test_module_context.py b/api/tests/opentrons/protocol_api/test_module_context.py index 6ce8928abc4..c57f1ff52dc 100644 --- a/api/tests/opentrons/protocol_api/test_module_context.py +++ b/api/tests/opentrons/protocol_api/test_module_context.py @@ -108,7 +108,7 @@ def test_load_labware( decoy.when(mock_labware_core.get_well_columns()).then_return([]) result = subject.load_labware( - name="infinite tip rack", + name="Infinite Tip Rack", label="it doesn't run out", namespace="ideal", version=101, diff --git a/api/tests/opentrons/protocol_api/test_parameter_context.py b/api/tests/opentrons/protocol_api/test_parameter_context.py index 4d839d72667..7dcc246f216 100644 --- a/api/tests/opentrons/protocol_api/test_parameter_context.py +++ b/api/tests/opentrons/protocol_api/test_parameter_context.py @@ -46,6 +46,9 @@ def subject(api_version: APIVersion) -> ParameterContext: def test_add_int(decoy: Decoy, subject: ParameterContext) -> None: """It should create and add an int parameter definition.""" + subject._parameters["other_param"] = decoy.mock( + cls=mock_parameter_definition.ParameterDefinition + ) param_def = decoy.mock(cls=mock_parameter_definition.ParameterDefinition) decoy.when(param_def.variable_name).then_return("my cool variable") decoy.when( @@ -60,6 +63,7 @@ def test_add_int(decoy: Decoy, subject: ParameterContext) -> None: unit="foot candles", ) ).then_return(param_def) + subject.add_int( display_name="abc", variable_name="xyz", @@ -70,11 +74,16 @@ def test_add_int(decoy: Decoy, subject: ParameterContext) -> None: description="blah blah blah", unit="foot candles", ) + assert param_def is subject._parameters["my cool variable"] + decoy.verify(mock_validation.validate_variable_name_unique("xyz", {"other_param"})) def test_add_float(decoy: Decoy, subject: ParameterContext) -> None: """It should create and add a float parameter definition.""" + subject._parameters["other_param"] = decoy.mock( + cls=mock_parameter_definition.ParameterDefinition + ) param_def = decoy.mock(cls=mock_parameter_definition.ParameterDefinition) decoy.when(param_def.variable_name).then_return("my cooler variable") decoy.when(mock_validation.ensure_float_value(12.3)).then_return(3.21) @@ -83,7 +92,6 @@ def test_add_float(decoy: Decoy, subject: ParameterContext) -> None: decoy.when( mock_validation.ensure_float_choices([{"display_name": "foo", "value": 4.2}]) ).then_return([{"display_name": "bar", "value": 2.4}]) - decoy.when( mock_parameter_definition.create_float_parameter( display_name="abc", @@ -96,6 +104,7 @@ def test_add_float(decoy: Decoy, subject: ParameterContext) -> None: unit="lux", ) ).then_return(param_def) + subject.add_float( display_name="abc", variable_name="xyz", @@ -106,11 +115,16 @@ def test_add_float(decoy: Decoy, subject: ParameterContext) -> None: description="blah blah blah", unit="lux", ) + assert param_def is subject._parameters["my cooler variable"] + decoy.verify(mock_validation.validate_variable_name_unique("xyz", {"other_param"})) def test_add_bool(decoy: Decoy, subject: ParameterContext) -> None: """It should create and add a boolean parameter definition.""" + subject._parameters["other_param"] = decoy.mock( + cls=mock_parameter_definition.ParameterDefinition + ) param_def = decoy.mock(cls=mock_parameter_definition.ParameterDefinition) decoy.when(param_def.variable_name).then_return("my coolest variable") decoy.when( @@ -125,17 +139,23 @@ def test_add_bool(decoy: Decoy, subject: ParameterContext) -> None: description="lorem ipsum", ) ).then_return(param_def) + subject.add_bool( display_name="cba", variable_name="zxy", default=False, description="lorem ipsum", ) + assert param_def is subject._parameters["my coolest variable"] + decoy.verify(mock_validation.validate_variable_name_unique("zxy", {"other_param"})) def test_add_string(decoy: Decoy, subject: ParameterContext) -> None: """It should create and add a string parameter definition.""" + subject._parameters["other_param"] = decoy.mock( + cls=mock_parameter_definition.ParameterDefinition + ) param_def = decoy.mock(cls=mock_parameter_definition.ParameterDefinition) decoy.when(param_def.variable_name).then_return("my slightly less cool variable") decoy.when( @@ -147,6 +167,7 @@ def test_add_string(decoy: Decoy, subject: ParameterContext) -> None: description="fee foo fum", ) ).then_return(param_def) + subject.add_str( display_name="jkl", variable_name="qwerty", @@ -154,7 +175,11 @@ def test_add_string(decoy: Decoy, subject: ParameterContext) -> None: choices=[{"display_name": "bar", "value": "aaa"}], description="fee foo fum", ) + assert param_def is subject._parameters["my slightly less cool variable"] + decoy.verify( + mock_validation.validate_variable_name_unique("qwerty", {"other_param"}) + ) def test_set_parameters(decoy: Decoy, subject: ParameterContext) -> None: @@ -200,5 +225,5 @@ def test_export_parameters_for_protocol( subject._parameters = {"foo": param_def_1, "bar": param_def_2} result = subject.export_parameters_for_protocol() - assert result.x == "a" # type: ignore [attr-defined] - assert result.y == 1.23 # type: ignore [attr-defined] + assert result.x == "a" # type: ignore[attr-defined] + assert result.y == 1.23 # type: ignore[attr-defined] diff --git a/api/tests/opentrons/protocol_api_old/test_context.py b/api/tests/opentrons/protocol_api_old/test_context.py index db45d3af6c6..c356c477f7f 100644 --- a/api/tests/opentrons/protocol_api_old/test_context.py +++ b/api/tests/opentrons/protocol_api_old/test_context.py @@ -85,7 +85,7 @@ async def test_motion(ctx, hardware): old_pos[Axis.X] = 0.0 old_pos[Axis.Y] = 0.0 old_pos[Axis.A] = 0.0 - old_pos[Axis.C] = 2.0 + old_pos[Axis.C] = 2.5 assert await hardware.current_position(instr._core.get_mount()) == pytest.approx( old_pos ) diff --git a/api/tests/opentrons/protocol_engine/clients/test_sync_client.py b/api/tests/opentrons/protocol_engine/clients/test_sync_client.py index d5d1f930cca..e4f5d7602ca 100644 --- a/api/tests/opentrons/protocol_engine/clients/test_sync_client.py +++ b/api/tests/opentrons/protocol_engine/clients/test_sync_client.py @@ -161,6 +161,30 @@ def test_load_labware( assert result == expected_result +def test_reload_labware( + decoy: Decoy, + transport: ChildThreadTransport, + subject: SyncClient, +) -> None: + """It should execute a reload labware command.""" + expected_request = commands.ReloadLabwareCreate( + params=commands.ReloadLabwareParams( + labwareId="some-labware-id", + ) + ) + + expected_result = commands.ReloadLabwareResult( + labwareId="some-labware-id", offsetId=None + ) + decoy.when(transport.execute_command(request=expected_request)).then_return( + expected_result + ) + result = subject.reload_labware( + labware_id="some-labware-id", + ) + assert result == expected_result + + def test_load_module( decoy: Decoy, transport: ChildThreadTransport, diff --git a/api/tests/opentrons/protocol_engine/commands/calibration/test_move_to_maintenance_position.py b/api/tests/opentrons/protocol_engine/commands/calibration/test_move_to_maintenance_position.py index 8cc9017a021..df58ab7dbc0 100644 --- a/api/tests/opentrons/protocol_engine/commands/calibration/test_move_to_maintenance_position.py +++ b/api/tests/opentrons/protocol_engine/commands/calibration/test_move_to_maintenance_position.py @@ -1,6 +1,6 @@ """Test for Calibration Set Up Position Implementation.""" from __future__ import annotations -from typing import TYPE_CHECKING, Mapping +from typing import TYPE_CHECKING import pytest from decoy import Decoy @@ -32,106 +32,68 @@ def subject( @pytest.mark.ot3_only -@pytest.mark.parametrize( - "maintenance_position, verify_axes", - [ - ( - MaintenancePosition.ATTACH_INSTRUMENT, - {Axis.Z_L: 400}, - ), - ( - MaintenancePosition.ATTACH_PLATE, - {Axis.Z_L: 90, Axis.Z_R: 105}, - ), - ], -) -async def test_calibration_move_to_location_implementation( +@pytest.mark.parametrize("mount_type", [MountType.LEFT, MountType.RIGHT]) +async def test_calibration_move_to_location_implementatio_for_attach_instrument( decoy: Decoy, subject: MoveToMaintenancePositionImplementation, state_view: StateView, ot3_hardware_api: OT3API, - maintenance_position: MaintenancePosition, - verify_axes: Mapping[Axis, float], + mount_type: MountType, ) -> None: """Command should get a move to target location and critical point and should verify move_to call.""" params = MoveToMaintenancePositionParams( - mount=MountType.LEFT, maintenancePosition=maintenance_position + mount=mount_type, maintenancePosition=MaintenancePosition.ATTACH_INSTRUMENT ) decoy.when( await ot3_hardware_api.gantry_position( Mount.LEFT, critical_point=CriticalPoint.MOUNT ) - ).then_return(Point(x=1, y=2, z=3)) - - decoy.when( - ot3_hardware_api.get_instrument_max_height( - Mount.LEFT, critical_point=CriticalPoint.MOUNT - ) - ).then_return(250) + ).then_return(Point(x=1, y=2, z=250)) decoy.when(ot3_hardware_api.get_instrument_max_height(Mount.LEFT)).then_return(300) result = await subject.execute(params=params) assert result == MoveToMaintenancePositionResult() + hw_mount = mount_type.to_hw_mount() decoy.verify( - await ot3_hardware_api.move_to( - mount=Mount.LEFT, - abs_position=Point(x=1, y=2, z=250), - critical_point=CriticalPoint.MOUNT, - ), - times=1, - ) - - decoy.verify( + await ot3_hardware_api.prepare_for_mount_movement(Mount.LEFT), + await ot3_hardware_api.retract(Mount.LEFT), await ot3_hardware_api.move_to( mount=Mount.LEFT, abs_position=Point(x=0, y=110, z=250), critical_point=CriticalPoint.MOUNT, ), - times=1, - ) - - decoy.verify( + await ot3_hardware_api.prepare_for_mount_movement(hw_mount), await ot3_hardware_api.move_axes( - position=verify_axes, + position={Axis.by_mount(hw_mount): 400}, + ), + await ot3_hardware_api.disengage_axes( + [Axis.by_mount(hw_mount)], ), - times=1, ) - if params.maintenancePosition == MaintenancePosition.ATTACH_INSTRUMENT: - decoy.verify( - await ot3_hardware_api.disengage_axes( - list(verify_axes.keys()), - ), - times=1, - ) - @pytest.mark.ot3_only -async def test_calibration_move_to_location_implementation_for_gripper( +@pytest.mark.parametrize("mount_type", [MountType.LEFT, MountType.RIGHT]) +async def test_calibration_move_to_location_implementatio_for_attach_plate( decoy: Decoy, subject: MoveToMaintenancePositionImplementation, state_view: StateView, ot3_hardware_api: OT3API, + mount_type: MountType, ) -> None: """Command should get a move to target location and critical point and should verify move_to call.""" params = MoveToMaintenancePositionParams( - mount=MountType.LEFT, maintenancePosition=MaintenancePosition.ATTACH_INSTRUMENT + mount=mount_type, maintenancePosition=MaintenancePosition.ATTACH_PLATE ) decoy.when( await ot3_hardware_api.gantry_position( Mount.LEFT, critical_point=CriticalPoint.MOUNT ) - ).then_return(Point(x=1, y=2, z=3)) - - decoy.when( - ot3_hardware_api.get_instrument_max_height( - Mount.LEFT, critical_point=CriticalPoint.MOUNT - ) - ).then_return(250) + ).then_return(Point(x=1, y=2, z=250)) decoy.when(ot3_hardware_api.get_instrument_max_height(Mount.LEFT)).then_return(300) @@ -139,21 +101,56 @@ async def test_calibration_move_to_location_implementation_for_gripper( assert result == MoveToMaintenancePositionResult() decoy.verify( + await ot3_hardware_api.prepare_for_mount_movement(Mount.LEFT), + await ot3_hardware_api.retract(Mount.LEFT), await ot3_hardware_api.move_to( mount=Mount.LEFT, - abs_position=Point(x=1, y=2, z=250), + abs_position=Point(x=0, y=110, z=250), critical_point=CriticalPoint.MOUNT, ), - times=1, + await ot3_hardware_api.move_axes( + position={ + Axis.Z_L: 90, + Axis.Z_R: 105, + } + ), + await ot3_hardware_api.disengage_axes( + [Axis.Z_L, Axis.Z_R], + ), + ) + + +@pytest.mark.ot3_only +async def test_calibration_move_to_location_implementation_for_gripper( + decoy: Decoy, + subject: MoveToMaintenancePositionImplementation, + state_view: StateView, + ot3_hardware_api: OT3API, +) -> None: + """Command should get a move to target location and critical point and should verify move_to call.""" + params = MoveToMaintenancePositionParams( + mount=MountType.EXTENSION, + maintenancePosition=MaintenancePosition.ATTACH_INSTRUMENT, ) + decoy.when( + await ot3_hardware_api.gantry_position( + Mount.LEFT, critical_point=CriticalPoint.MOUNT + ) + ).then_return(Point(x=1, y=2, z=250)) + decoy.when(ot3_hardware_api.get_instrument_max_height(Mount.LEFT)).then_return(300) + + result = await subject.execute(params=params) + assert result == MoveToMaintenancePositionResult() + decoy.verify( + await ot3_hardware_api.prepare_for_mount_movement(Mount.LEFT), + await ot3_hardware_api.retract(Mount.LEFT), await ot3_hardware_api.move_to( mount=Mount.LEFT, abs_position=Point(x=0, y=110, z=250), critical_point=CriticalPoint.MOUNT, ), - times=1, ) decoy.verify( @@ -162,7 +159,6 @@ async def test_calibration_move_to_location_implementation_for_gripper( ), times=0, ) - decoy.verify( await ot3_hardware_api.disengage_axes( [Axis.Z_G], diff --git a/api/tests/opentrons/protocol_engine/commands/test_hash_command_params.py b/api/tests/opentrons/protocol_engine/commands/test_hash_command_params.py index 098ce53c321..e881a13a9fb 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_hash_command_params.py +++ b/api/tests/opentrons/protocol_engine/commands/test_hash_command_params.py @@ -1,8 +1,11 @@ """Tests for hash_command_params.""" +import pytest from opentrons.protocol_engine import CommandIntent from opentrons.protocol_engine import commands -from opentrons.protocol_engine.commands.hash_command_params import hash_command_params +from opentrons.protocol_engine.commands.hash_command_params import ( + hash_protocol_command_params, +) def test_equivalent_commands() -> None: @@ -20,10 +23,14 @@ def test_equivalent_commands() -> None: params=commands.WaitForDurationParams(seconds=123) ) - assert hash_command_params(b, None) == hash_command_params(c, None) + assert hash_protocol_command_params(b, None) == hash_protocol_command_params( + c, None + ) - a_hash = hash_command_params(a, None) - assert hash_command_params(b, a_hash) == hash_command_params(c, a_hash) + a_hash = hash_protocol_command_params(a, None) + assert hash_protocol_command_params(b, a_hash) == hash_protocol_command_params( + c, a_hash + ) def test_nonequivalent_commands() -> None: @@ -32,33 +39,39 @@ def test_nonequivalent_commands() -> None: params=commands.BlowOutInPlaceParams( pipetteId="abc123", flowRate=123, - ) + ), + intent=CommandIntent.PROTOCOL, ) b = commands.WaitForDurationCreate( params=commands.WaitForDurationParams(seconds=123) ) - assert hash_command_params(a, None) != hash_command_params(b, None) + assert hash_protocol_command_params(a, None) != hash_protocol_command_params( + b, None + ) def test_repeated_commands() -> None: """Repeated commands should hash differently, even though they're equivalent in isolation.""" a = commands.WaitForDurationCreate( - params=commands.WaitForDurationParams(seconds=123) + params=commands.WaitForDurationParams(seconds=123), + intent=CommandIntent.PROTOCOL, ) b = commands.WaitForDurationCreate( - params=commands.WaitForDurationParams(seconds=123) + params=commands.WaitForDurationParams(seconds=123), + intent=CommandIntent.PROTOCOL, ) - a_hash = hash_command_params(a, None) - b_hash = hash_command_params(b, a_hash) + a_hash = hash_protocol_command_params(a, None) + b_hash = hash_protocol_command_params(b, a_hash) assert a_hash != b_hash -def test_setup_command() -> None: - """Setup commands should always hash to None.""" +@pytest.mark.parametrize("command_intent", [CommandIntent.SETUP, CommandIntent.FIXIT]) +def test_setup_and_fixit_command(command_intent: CommandIntent) -> None: + """Setup and fixit commands should always skip hashing.""" setup_command = commands.WaitForDurationCreate( params=commands.WaitForDurationParams(seconds=123), - intent=CommandIntent.SETUP, + intent=command_intent, ) - assert hash_command_params(setup_command, None) is None + assert hash_protocol_command_params(setup_command, None) is None diff --git a/api/tests/opentrons/protocol_engine/commands/test_load_module.py b/api/tests/opentrons/protocol_engine/commands/test_load_module.py index 84be22d4661..65306f34adc 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_load_module.py +++ b/api/tests/opentrons/protocol_engine/commands/test_load_module.py @@ -1,9 +1,11 @@ """Test load module command.""" import pytest +from typing import cast from decoy import Decoy from opentrons.protocol_engine.errors import LocationIsOccupiedError from opentrons.protocol_engine.state import StateView +from opentrons_shared_data.robot.dev_types import RobotType from opentrons.types import DeckSlotName from opentrons.protocol_engine.types import ( DeckSlotLocation, @@ -11,12 +13,30 @@ ModuleDefinition, ) from opentrons.protocol_engine.execution import EquipmentHandler, LoadedModuleData +from opentrons.protocol_engine import ModuleModel as EngineModuleModel +from opentrons.hardware_control.modules import ModuleType from opentrons.protocol_engine.commands.load_module import ( LoadModuleParams, LoadModuleResult, LoadModuleImplementation, ) +from opentrons.hardware_control.modules.types import ( + ModuleModel as HardwareModuleModel, + TemperatureModuleModel, + MagneticModuleModel, + ThermocyclerModuleModel, + HeaterShakerModuleModel, +) +from opentrons_shared_data.deck.dev_types import ( + DeckDefinitionV5, + SlotDefV3, +) +from opentrons_shared_data.deck import load as load_deck +from opentrons.protocols.api_support.deck_type import ( + STANDARD_OT2_DECK, + STANDARD_OT3_DECK, +) async def test_load_module_implementation( @@ -29,19 +49,29 @@ async def test_load_module_implementation( subject = LoadModuleImplementation(equipment=equipment, state_view=state_view) data = LoadModuleParams( - model=ModuleModel.TEMPERATURE_MODULE_V1, - location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1), + model=ModuleModel.TEMPERATURE_MODULE_V2, + location=DeckSlotLocation(slotName=DeckSlotName.SLOT_D1), moduleId="some-id", ) + + deck_def = load_deck(STANDARD_OT3_DECK, 5) + + decoy.when(state_view.addressable_areas.state.deck_definition).then_return(deck_def) + decoy.when( + state_view.addressable_areas.get_cutout_id_by_deck_slot_name( + DeckSlotName.SLOT_D1 + ) + ).then_return("cutout" + DeckSlotName.SLOT_D1.value) + decoy.when( state_view.geometry.ensure_location_not_occupied( - DeckSlotLocation(slotName=DeckSlotName.SLOT_1) + DeckSlotLocation(slotName=DeckSlotName.SLOT_D1) ) ).then_return(DeckSlotLocation(slotName=DeckSlotName.SLOT_2)) decoy.when( await equipment.load_module( - model=ModuleModel.TEMPERATURE_MODULE_V1, + model=ModuleModel.TEMPERATURE_MODULE_V2, location=DeckSlotLocation(slotName=DeckSlotName.SLOT_2), module_id="some-id", ) @@ -73,12 +103,22 @@ async def test_load_module_implementation_mag_block( data = LoadModuleParams( model=ModuleModel.MAGNETIC_BLOCK_V1, - location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1), + location=DeckSlotLocation(slotName=DeckSlotName.SLOT_D1), moduleId="some-id", ) + + deck_def = load_deck(STANDARD_OT3_DECK, 5) + + decoy.when(state_view.addressable_areas.state.deck_definition).then_return(deck_def) + decoy.when( + state_view.addressable_areas.get_cutout_id_by_deck_slot_name( + DeckSlotName.SLOT_D1 + ) + ).then_return("cutout" + DeckSlotName.SLOT_D1.value) + decoy.when( state_view.geometry.ensure_location_not_occupied( - DeckSlotLocation(slotName=DeckSlotName.SLOT_1) + DeckSlotLocation(slotName=DeckSlotName.SLOT_D1) ) ).then_return(DeckSlotLocation(slotName=DeckSlotName.SLOT_2)) @@ -114,16 +154,162 @@ async def test_load_module_raises_if_location_occupied( subject = LoadModuleImplementation(equipment=equipment, state_view=state_view) data = LoadModuleParams( - model=ModuleModel.TEMPERATURE_MODULE_V1, - location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1), + model=ModuleModel.TEMPERATURE_MODULE_V2, + location=DeckSlotLocation(slotName=DeckSlotName.SLOT_D1), moduleId="some-id", ) + deck_def = load_deck(STANDARD_OT3_DECK, 5) + + decoy.when(state_view.addressable_areas.state.deck_definition).then_return(deck_def) + decoy.when( + state_view.addressable_areas.get_cutout_id_by_deck_slot_name( + DeckSlotName.SLOT_D1 + ) + ).then_return("cutout" + DeckSlotName.SLOT_D1.value) + decoy.when( state_view.geometry.ensure_location_not_occupied( - DeckSlotLocation(slotName=DeckSlotName.SLOT_1) + DeckSlotLocation(slotName=DeckSlotName.SLOT_D1) ) ).then_raise(LocationIsOccupiedError("Get your own spot!")) with pytest.raises(LocationIsOccupiedError): await subject.execute(data) + + +@pytest.mark.parametrize( + ( + "requested_model", + "engine_model", + "deck_def", + "slot_name", + "robot_type", + ), + [ + ( + TemperatureModuleModel.TEMPERATURE_V2, + EngineModuleModel.TEMPERATURE_MODULE_V2, + load_deck(STANDARD_OT3_DECK, 5), + DeckSlotName.SLOT_D2, + "OT-3 Standard", + ), + ( + ThermocyclerModuleModel.THERMOCYCLER_V1, + EngineModuleModel.THERMOCYCLER_MODULE_V1, + load_deck(STANDARD_OT2_DECK, 5), + DeckSlotName.SLOT_1, + "OT-2 Standard", + ), + ( + ThermocyclerModuleModel.THERMOCYCLER_V2, + EngineModuleModel.THERMOCYCLER_MODULE_V2, + load_deck(STANDARD_OT3_DECK, 5), + DeckSlotName.SLOT_A2, + "OT-3 Standard", + ), + ( + HeaterShakerModuleModel.HEATER_SHAKER_V1, + EngineModuleModel.HEATER_SHAKER_MODULE_V1, + load_deck(STANDARD_OT3_DECK, 5), + DeckSlotName.SLOT_A2, + "OT-3 Standard", + ), + ], +) +async def test_load_module_raises_wrong_location( + decoy: Decoy, + equipment: EquipmentHandler, + state_view: StateView, + requested_model: HardwareModuleModel, + engine_model: EngineModuleModel, + deck_def: DeckDefinitionV5, + slot_name: DeckSlotName, + robot_type: RobotType, +) -> None: + """It should issue a load module engine command.""" + subject = LoadModuleImplementation(equipment=equipment, state_view=state_view) + + data = LoadModuleParams( + model=engine_model, + location=DeckSlotLocation(slotName=slot_name), + moduleId="some-id", + ) + + decoy.when(state_view.config.robot_type).then_return(robot_type) + + if robot_type == "OT-2 Standard": + decoy.when( + state_view.addressable_areas.get_slot_definition(slot_name.id) + ).then_return(cast(SlotDefV3, {"compatibleModuleTypes": []})) + else: + decoy.when(state_view.addressable_areas.state.deck_definition).then_return( + deck_def + ) + decoy.when( + state_view.addressable_areas.get_cutout_id_by_deck_slot_name(slot_name) + ).then_return("cutout" + slot_name.value) + + with pytest.raises( + ValueError, + match=f"A {ModuleType.from_model(model=requested_model).value} cannot be loaded into slot {slot_name}", + ): + await subject.execute(data) + + +@pytest.mark.parametrize( + ( + "requested_model", + "engine_model", + "deck_def", + "slot_name", + "robot_type", + ), + [ + ( + MagneticModuleModel.MAGNETIC_V2, + EngineModuleModel.MAGNETIC_MODULE_V2, + load_deck(STANDARD_OT3_DECK, 5), + DeckSlotName.SLOT_A2, + "OT-3 Standard", + ), + ], +) +async def test_load_module_raises_module_fixture_id_does_not_exist( + decoy: Decoy, + equipment: EquipmentHandler, + state_view: StateView, + requested_model: HardwareModuleModel, + engine_model: EngineModuleModel, + deck_def: DeckDefinitionV5, + slot_name: DeckSlotName, + robot_type: RobotType, +) -> None: + """It should issue a load module engine command and raise an error for unmatched fixtures.""" + subject = LoadModuleImplementation(equipment=equipment, state_view=state_view) + + data = LoadModuleParams( + model=engine_model, + location=DeckSlotLocation(slotName=slot_name), + moduleId="some-id", + ) + + decoy.when(state_view.config.robot_type).then_return(robot_type) + + if robot_type == "OT-2 Standard": + decoy.when( + state_view.addressable_areas.get_slot_definition(slot_name.id) + ).then_return(cast(SlotDefV3, {"compatibleModuleTypes": []})) + else: + decoy.when(state_view.addressable_areas.state.deck_definition).then_return( + deck_def + ) + decoy.when( + state_view.addressable_areas.get_cutout_id_by_deck_slot_name(slot_name) + ).then_return("cutout" + slot_name.value) + + with pytest.raises( + ValueError, + match=f"Module Type {ModuleType.from_model(requested_model).value} does not have a related fixture ID.", + ): + await subject.execute(data) diff --git a/api/tests/opentrons/protocol_engine/commands/test_reload_labware.py b/api/tests/opentrons/protocol_engine/commands/test_reload_labware.py new file mode 100644 index 00000000000..556d4975786 --- /dev/null +++ b/api/tests/opentrons/protocol_engine/commands/test_reload_labware.py @@ -0,0 +1,85 @@ +"""Test load labware commands.""" +import inspect +import pytest + +from decoy import Decoy + +from opentrons.types import DeckSlotName +from opentrons.protocols.models import LabwareDefinition + +from opentrons.protocol_engine.errors import ( + LabwareNotLoadedError, +) + +from opentrons.protocol_engine.types import ( + DeckSlotLocation, +) +from opentrons.protocol_engine.execution import ReloadedLabwareData, EquipmentHandler +from opentrons.protocol_engine.resources import labware_validation +from opentrons.protocol_engine.state import StateView + +from opentrons.protocol_engine.commands.reload_labware import ( + ReloadLabwareParams, + ReloadLabwareResult, + ReloadLabwareImplementation, +) + + +@pytest.fixture(autouse=True) +def patch_mock_labware_validation( + decoy: Decoy, monkeypatch: pytest.MonkeyPatch +) -> None: + """Mock out move_types.py functions.""" + for name, func in inspect.getmembers(labware_validation, inspect.isfunction): + monkeypatch.setattr(labware_validation, name, decoy.mock(func=func)) + + +async def test_reload_labware_implementation( + decoy: Decoy, + well_plate_def: LabwareDefinition, + equipment: EquipmentHandler, + state_view: StateView, +) -> None: + """A ReloadLabware command should have an execution implementation.""" + subject = ReloadLabwareImplementation(equipment=equipment, state_view=state_view) + + data = ReloadLabwareParams( + labwareId="my-labware-id", + ) + + decoy.when(await equipment.reload_labware(labware_id="my-labware-id",)).then_return( + ReloadedLabwareData( + location=DeckSlotLocation(slotName=DeckSlotName.SLOT_4), + offsetId="labware-offset-id", + ) + ) + + result = await subject.execute(data) + + assert result == ReloadLabwareResult( + labwareId="my-labware-id", + offsetId="labware-offset-id", + ) + + +async def test_reload_labware_raises_labware_does_not_exist( + decoy: Decoy, + well_plate_def: LabwareDefinition, + equipment: EquipmentHandler, + state_view: StateView, +) -> None: + """A ReloadLabware command should raise if the specified labware is not loaded.""" + subject = ReloadLabwareImplementation(equipment=equipment, state_view=state_view) + + data = ReloadLabwareParams( + labwareId="my-labware-id", + ) + + decoy.when( + await equipment.reload_labware( + labware_id="my-labware-id", + ) + ).then_raise(LabwareNotLoadedError("What labware is this!")) + + with pytest.raises(LabwareNotLoadedError): + await subject.execute(data) diff --git a/api/tests/opentrons/protocol_engine/conftest.py b/api/tests/opentrons/protocol_engine/conftest.py index dfd59089c2d..ab23f7e9e08 100644 --- a/api/tests/opentrons/protocol_engine/conftest.py +++ b/api/tests/opentrons/protocol_engine/conftest.py @@ -7,7 +7,7 @@ from opentrons_shared_data import load_shared_data from opentrons_shared_data.deck import load as load_deck -from opentrons_shared_data.deck.dev_types import DeckDefinitionV4 +from opentrons_shared_data.deck.dev_types import DeckDefinitionV5 from opentrons_shared_data.labware import load_definition from opentrons_shared_data.pipette import pipette_definition from opentrons.protocols.models import LabwareDefinition @@ -57,21 +57,21 @@ def ot3_hardware_api(decoy: Decoy) -> OT3API: @pytest.fixture(scope="session") -def ot2_standard_deck_def() -> DeckDefinitionV4: +def ot2_standard_deck_def() -> DeckDefinitionV5: """Get the OT-2 standard deck definition.""" - return load_deck(STANDARD_OT2_DECK, 4) + return load_deck(STANDARD_OT2_DECK, 5) @pytest.fixture(scope="session") -def ot2_short_trash_deck_def() -> DeckDefinitionV4: +def ot2_short_trash_deck_def() -> DeckDefinitionV5: """Get the OT-2 short-trash deck definition.""" - return load_deck(SHORT_TRASH_DECK, 4) + return load_deck(SHORT_TRASH_DECK, 5) @pytest.fixture(scope="session") -def ot3_standard_deck_def() -> DeckDefinitionV4: +def ot3_standard_deck_def() -> DeckDefinitionV5: """Get the OT-2 standard deck definition.""" - return load_deck(STANDARD_OT3_DECK, 4) + return load_deck(STANDARD_OT3_DECK, 5) @pytest.fixture(scope="session") diff --git a/api/tests/opentrons/protocol_engine/execution/test_command_executor.py b/api/tests/opentrons/protocol_engine/execution/test_command_executor.py index 2cd753093f9..8f4433a9ebe 100644 --- a/api/tests/opentrons/protocol_engine/execution/test_command_executor.py +++ b/api/tests/opentrons/protocol_engine/execution/test_command_executor.py @@ -242,9 +242,7 @@ class _TestCommand(BaseCommand[_TestCommandParams, _TestCommandResult]): params: _TestCommandParams result: Optional[_TestCommandResult] - @property - def _ImplementationCls(self) -> Type[_TestCommandImpl]: - return TestCommandImplCls + _ImplementationCls: Type[_TestCommandImpl] = TestCommandImplCls command_params = _TestCommandParams() command_result = _TestCommandResult() @@ -360,8 +358,8 @@ def _ImplementationCls(self) -> Type[_TestCommandImpl]: False, ), ( - EStopActivatedError("oh no"), - matchers.ErrorMatching(PE_EStopActivatedError, match="oh no"), + EStopActivatedError(), + matchers.ErrorMatching(PE_EStopActivatedError), True, ), ( @@ -407,9 +405,7 @@ class _TestCommand(BaseCommand[_TestCommandParams, _TestCommandResult]): params: _TestCommandParams result: Optional[_TestCommandResult] - @property - def _ImplementationCls(self) -> Type[_TestCommandImpl]: - return TestCommandImplCls + _ImplementationCls: Type[_TestCommandImpl] = TestCommandImplCls command_params = _TestCommandParams() diff --git a/api/tests/opentrons/protocol_engine/execution/test_equipment_handler.py b/api/tests/opentrons/protocol_engine/execution/test_equipment_handler.py index 69a249ebfc2..1177894e977 100644 --- a/api/tests/opentrons/protocol_engine/execution/test_equipment_handler.py +++ b/api/tests/opentrons/protocol_engine/execution/test_equipment_handler.py @@ -22,7 +22,6 @@ from opentrons.protocols.models import LabwareDefinition from opentrons.protocol_engine import errors -from opentrons.protocol_engine.actions import ActionDispatcher from opentrons.protocol_engine.types import ( DeckSlotLocation, DeckType, @@ -84,12 +83,6 @@ def state_store(decoy: Decoy) -> StateStore: return decoy.mock(cls=StateStore) -@pytest.fixture -def action_dispatcher(decoy: Decoy) -> ActionDispatcher: - """Get a mocked out ActionDispatcher instance.""" - return decoy.mock(cls=ActionDispatcher) - - @pytest.fixture def model_utils(decoy: Decoy) -> ModelUtils: """Get a mocked out ModelUtils instance.""" @@ -166,7 +159,6 @@ def virtual_pipette_data_provider( def subject( hardware_api: HardwareControlAPI, state_store: StateStore, - action_dispatcher: ActionDispatcher, labware_data_provider: LabwareDataProvider, module_data_provider: ModuleDataProvider, model_utils: ModelUtils, @@ -176,7 +168,6 @@ def subject( return EquipmentHandler( hardware_api=hardware_api, state_store=state_store, - action_dispatcher=action_dispatcher, labware_data_provider=labware_data_provider, module_data_provider=module_data_provider, model_utils=model_utils, @@ -614,7 +605,6 @@ async def test_load_pipette( model_utils: ModelUtils, hardware_api: HardwareControlAPI, state_store: StateStore, - action_dispatcher: ActionDispatcher, loaded_static_pipette_data: LoadedStaticPipetteData, subject: EquipmentHandler, ) -> None: @@ -665,7 +655,6 @@ async def test_load_pipette_96_channels( model_utils: ModelUtils, hardware_api: HardwareControlAPI, state_store: StateStore, - action_dispatcher: ActionDispatcher, loaded_static_pipette_data: LoadedStaticPipetteData, subject: EquipmentHandler, ) -> None: @@ -702,7 +691,6 @@ async def test_load_pipette_uses_provided_id( decoy: Decoy, hardware_api: HardwareControlAPI, state_store: StateStore, - action_dispatcher: ActionDispatcher, loaded_static_pipette_data: LoadedStaticPipetteData, subject: EquipmentHandler, ) -> None: @@ -734,7 +722,6 @@ async def test_load_pipette_use_virtual( decoy: Decoy, model_utils: ModelUtils, state_store: StateStore, - action_dispatcher: ActionDispatcher, loaded_static_pipette_data: LoadedStaticPipetteData, subject: EquipmentHandler, virtual_pipette_data_provider: pipette_data_provider.VirtualPipetteDataProvider, @@ -837,6 +824,7 @@ async def test_load_module( HardwareModule(serial_number="serial-1", definition=tempdeck_v1_def), HardwareModule(serial_number="serial-2", definition=tempdeck_v2_def), ], + expected_serial_number=None, ) ).then_return(HardwareModule(serial_number="serial-1", definition=tempdeck_v1_def)) diff --git a/api/tests/opentrons/protocol_engine/execution/test_tip_handler.py b/api/tests/opentrons/protocol_engine/execution/test_tip_handler.py index 6a84810ff61..e7e0284debe 100644 --- a/api/tests/opentrons/protocol_engine/execution/test_tip_handler.py +++ b/api/tests/opentrons/protocol_engine/execution/test_tip_handler.py @@ -413,11 +413,11 @@ async def test_verify_tip_presence_on_ot3( decoy.when(mock_state_view.pipettes.get_mount("pipette-id")).then_return( MountType.LEFT ) - await subject.verify_tip_presence("pipette-id", expected) + await subject.verify_tip_presence("pipette-id", expected, None) decoy.verify( await ot3_hardware_api.verify_tip_presence( - Mount.LEFT, expected.to_hw_state() + Mount.LEFT, expected.to_hw_state(), None ) ) diff --git a/api/tests/opentrons/protocol_engine/resources/test_deck_configuration_provider.py b/api/tests/opentrons/protocol_engine/resources/test_deck_configuration_provider.py index 8071cc98a66..12b324955be 100644 --- a/api/tests/opentrons/protocol_engine/resources/test_deck_configuration_provider.py +++ b/api/tests/opentrons/protocol_engine/resources/test_deck_configuration_provider.py @@ -5,7 +5,7 @@ from pytest_lazyfixture import lazy_fixture # type: ignore[import-untyped] from opentrons_shared_data.deck import load as load_deck -from opentrons_shared_data.deck.dev_types import DeckDefinitionV4 +from opentrons_shared_data.deck.dev_types import DeckDefinitionV5 from opentrons.types import DeckSlotName @@ -13,7 +13,6 @@ FixtureDoesNotExistError, CutoutDoesNotExistError, AddressableAreaDoesNotExistError, - FixtureDoesNotProvideAreasError, ) from opentrons.protocol_engine.types import ( AddressableArea, @@ -33,21 +32,21 @@ @pytest.fixture(scope="session") -def ot2_standard_deck_def() -> DeckDefinitionV4: +def ot2_standard_deck_def() -> DeckDefinitionV5: """Get the OT-2 standard deck definition.""" - return load_deck(STANDARD_OT2_DECK, 4) + return load_deck(STANDARD_OT2_DECK, 5) @pytest.fixture(scope="session") -def ot2_short_trash_deck_def() -> DeckDefinitionV4: +def ot2_short_trash_deck_def() -> DeckDefinitionV5: """Get the OT-2 standard deck definition.""" - return load_deck(SHORT_TRASH_DECK, 4) + return load_deck(SHORT_TRASH_DECK, 5) @pytest.fixture(scope="session") -def ot3_standard_deck_def() -> DeckDefinitionV4: +def ot3_standard_deck_def() -> DeckDefinitionV5: """Get the OT-2 standard deck definition.""" - return load_deck(STANDARD_OT3_DECK, 4) + return load_deck(STANDARD_OT3_DECK, 5) @pytest.mark.parametrize( @@ -73,7 +72,7 @@ def ot3_standard_deck_def() -> DeckDefinitionV4: def test_get_cutout_position( cutout_id: str, expected_deck_point: DeckPoint, - deck_def: DeckDefinitionV4, + deck_def: DeckDefinitionV5, ) -> None: """It should get the deck position for the requested cutout id.""" cutout_position = subject.get_cutout_position(cutout_id, deck_def) @@ -81,7 +80,7 @@ def test_get_cutout_position( def test_get_cutout_position_raises( - ot3_standard_deck_def: DeckDefinitionV4, + ot3_standard_deck_def: DeckDefinitionV5, ) -> None: """It should raise if there is no cutout with that ID in the deck definition.""" with pytest.raises(CutoutDoesNotExistError): @@ -107,7 +106,7 @@ def test_get_cutout_position_raises( def test_get_cutout_fixture( cutout_fixture_id: str, expected_display_name: str, - deck_def: DeckDefinitionV4, + deck_def: DeckDefinitionV5, ) -> None: """It should get the cutout fixture given the cutout fixture id.""" cutout_fixture = subject.get_cutout_fixture(cutout_fixture_id, deck_def) @@ -115,7 +114,7 @@ def test_get_cutout_fixture( def test_get_cutout_fixture_raises( - ot3_standard_deck_def: DeckDefinitionV4, + ot3_standard_deck_def: DeckDefinitionV5, ) -> None: """It should raise if the given cutout fixture id does not exist.""" with pytest.raises(FixtureDoesNotExistError): @@ -149,7 +148,7 @@ def test_get_provided_addressable_area_names( cutout_fixture_id: str, cutout_id: str, expected_areas: List[str], - deck_def: DeckDefinitionV4, + deck_def: DeckDefinitionV5, ) -> None: """It should get the provided addressable area for the cutout fixture and cutout.""" provided_addressable_areas = subject.get_provided_addressable_area_names( @@ -158,16 +157,6 @@ def test_get_provided_addressable_area_names( assert provided_addressable_areas == expected_areas -def test_get_provided_addressable_area_raises( - ot3_standard_deck_def: DeckDefinitionV4, -) -> None: - """It should raise if the cutout fixture does not provide areas for the given cutout id.""" - with pytest.raises(FixtureDoesNotProvideAreasError): - subject.get_provided_addressable_area_names( - "singleRightSlot", "theFunCutout", ot3_standard_deck_def - ) - - @pytest.mark.parametrize( ( "addressable_area_name", @@ -223,7 +212,7 @@ def test_get_potential_cutout_fixtures( addressable_area_name: str, expected_cutout_id: str, expected_potential_fixtures: Set[PotentialCutoutFixture], - deck_def: DeckDefinitionV4, + deck_def: DeckDefinitionV5, ) -> None: """It should get a cutout id and a set of potential cutout fixtures for an addressable area name.""" cutout_id, potential_fixtures = subject.get_potential_cutout_fixtures( @@ -234,7 +223,7 @@ def test_get_potential_cutout_fixtures( def test_get_potential_cutout_fixtures_raises( - ot3_standard_deck_def: DeckDefinitionV4, + ot3_standard_deck_def: DeckDefinitionV5, ) -> None: """It should raise if there is no fixtures that provide the requested area.""" with pytest.raises(AddressableAreaDoesNotExistError): @@ -288,11 +277,7 @@ def test_get_potential_cutout_fixtures_raises( display_name="Slot D1", bounding_box=Dimensions(x=128.0, y=86.0, z=0), position=AddressableOffsetVector(x=1, y=2, z=3), - compatible_module_types=[ - "temperatureModuleType", - "heaterShakerModuleType", - "magneticBlockType", - ], + compatible_module_types=[], ), lazy_fixture("ot3_standard_deck_def"), ), @@ -327,7 +312,7 @@ def test_get_potential_cutout_fixtures_raises( def test_get_addressable_area_from_name( addressable_area_name: str, expected_addressable_area: AddressableArea, - deck_def: DeckDefinitionV4, + deck_def: DeckDefinitionV5, ) -> None: """It should get the deck position for the requested cutout id.""" addressable_area = subject.get_addressable_area_from_name( @@ -337,7 +322,7 @@ def test_get_addressable_area_from_name( def test_get_addressable_area_from_name_raises( - ot3_standard_deck_def: DeckDefinitionV4, + ot3_standard_deck_def: DeckDefinitionV5, ) -> None: """It should raise if there is no addressable area by that name in the deck.""" with pytest.raises(AddressableAreaDoesNotExistError): diff --git a/api/tests/opentrons/protocol_engine/resources/test_deck_data_provider.py b/api/tests/opentrons/protocol_engine/resources/test_deck_data_provider.py index f587d7ce5dd..bd720777ed6 100644 --- a/api/tests/opentrons/protocol_engine/resources/test_deck_data_provider.py +++ b/api/tests/opentrons/protocol_engine/resources/test_deck_data_provider.py @@ -3,7 +3,7 @@ from pytest_lazyfixture import lazy_fixture # type: ignore[import-untyped] from decoy import Decoy -from opentrons_shared_data.deck.dev_types import DeckDefinitionV4 +from opentrons_shared_data.deck.dev_types import DeckDefinitionV5 from opentrons.protocols.models import LabwareDefinition from opentrons.types import DeckSlotName @@ -31,7 +31,7 @@ def mock_labware_data_provider(decoy: Decoy) -> LabwareDataProvider: ) async def test_get_deck_definition( deck_type: DeckType, - expected_definition: DeckDefinitionV4, + expected_definition: DeckDefinitionV5, mock_labware_data_provider: LabwareDataProvider, ) -> None: """It should be able to load the correct deck definition.""" @@ -44,7 +44,7 @@ async def test_get_deck_definition( async def test_get_deck_labware_fixtures_ot2_standard( decoy: Decoy, - ot2_standard_deck_def: DeckDefinitionV4, + ot2_standard_deck_def: DeckDefinitionV5, ot2_fixed_trash_def: LabwareDefinition, mock_labware_data_provider: LabwareDataProvider, ) -> None: @@ -74,7 +74,7 @@ async def test_get_deck_labware_fixtures_ot2_standard( async def test_get_deck_labware_fixtures_ot2_short_trash( decoy: Decoy, - ot2_short_trash_deck_def: DeckDefinitionV4, + ot2_short_trash_deck_def: DeckDefinitionV5, ot2_short_fixed_trash_def: LabwareDefinition, mock_labware_data_provider: LabwareDataProvider, ) -> None: @@ -104,7 +104,7 @@ async def test_get_deck_labware_fixtures_ot2_short_trash( async def test_get_deck_labware_fixtures_ot3_standard( decoy: Decoy, - ot3_standard_deck_def: DeckDefinitionV4, + ot3_standard_deck_def: DeckDefinitionV5, ot3_fixed_trash_def: LabwareDefinition, mock_labware_data_provider: LabwareDataProvider, ) -> None: diff --git a/api/tests/opentrons/protocol_engine/resources/test_pipette_data_provider.py b/api/tests/opentrons/protocol_engine/resources/test_pipette_data_provider.py index f691e8bd581..049441da52a 100644 --- a/api/tests/opentrons/protocol_engine/resources/test_pipette_data_provider.py +++ b/api/tests/opentrons/protocol_engine/resources/test_pipette_data_provider.py @@ -33,7 +33,7 @@ def test_get_virtual_pipette_static_config( ) assert result == LoadedStaticPipetteData( - model="p20_single_v2.0", + model="p20_single_v2.2", display_name="P20 Single-Channel GEN2", min_volume=1, max_volume=20.0, @@ -69,7 +69,7 @@ def test_configure_virtual_pipette_for_volume( PipetteNameType.P50_SINGLE_FLEX.value, "my-pipette" ) assert result1 == LoadedStaticPipetteData( - model="p50_single_v3.0", + model="p50_single_v3.6", display_name="Flex 1-Channel 50 μL", min_volume=5, max_volume=50.0, @@ -77,9 +77,9 @@ def test_configure_virtual_pipette_for_volume( nozzle_offset_z=-259.15, home_position=230.15, flow_rates=FlowRates( - default_blow_out={"2.14": 4.0}, - default_aspirate={"2.14": 8.0}, - default_dispense={"2.14": 8.0}, + default_blow_out={"2.14": 57}, + default_aspirate={"2.14": 35}, + default_dispense={"2.14": 57}, ), tip_configuration_lookup_table=result1.tip_configuration_lookup_table, nominal_tip_overlap=result1.nominal_tip_overlap, @@ -94,7 +94,7 @@ def test_configure_virtual_pipette_for_volume( PipetteNameType.P50_SINGLE_FLEX.value, "my-pipette" ) assert result2 == LoadedStaticPipetteData( - model="p50_single_v3.0", + model="p50_single_v3.6", display_name="Flex 1-Channel 50 μL", min_volume=1, max_volume=30, @@ -102,9 +102,9 @@ def test_configure_virtual_pipette_for_volume( nozzle_offset_z=-259.15, home_position=230.15, flow_rates=FlowRates( - default_blow_out={"2.14": 4.0}, - default_aspirate={"2.14": 8.0}, - default_dispense={"2.14": 8.0}, + default_blow_out={"2.14": 26.7}, + default_aspirate={"2.14": 26.7}, + default_dispense={"2.14": 26.7}, ), tip_configuration_lookup_table=result2.tip_configuration_lookup_table, nominal_tip_overlap=result2.nominal_tip_overlap, @@ -162,19 +162,19 @@ def test_load_virtual_pipette_nozzle_layout( assert result.configuration.value == "FULL" subject_instance.configure_virtual_pipette_nozzle_layout( - "my-96-pipette", "p1000_96_v3.5", "A1", "A12", "A1" + "my-96-pipette", "p1000_96_v3.6", "A1", "A12", "A1" ) result = subject_instance.get_nozzle_layout_for_pipette("my-96-pipette") assert result.configuration.value == "ROW" subject_instance.configure_virtual_pipette_nozzle_layout( - "my-96-pipette", "p1000_96_v3.5", "A1", "A1" + "my-96-pipette", "p1000_96_v3.6", "A1", "A1" ) result = subject_instance.get_nozzle_layout_for_pipette("my-96-pipette") assert result.configuration.value == "SINGLE" subject_instance.configure_virtual_pipette_nozzle_layout( - "my-96-pipette", "p1000_96_v3.5", "A1", "H1" + "my-96-pipette", "p1000_96_v3.6", "A1", "H1" ) result = subject_instance.get_nozzle_layout_for_pipette("my-96-pipette") assert result.configuration.value == "COLUMN" diff --git a/api/tests/opentrons/protocol_engine/state/command_fixtures.py b/api/tests/opentrons/protocol_engine/state/command_fixtures.py index 191dd49bd48..98ee48e724d 100644 --- a/api/tests/opentrons/protocol_engine/state/command_fixtures.py +++ b/api/tests/opentrons/protocol_engine/state/command_fixtures.py @@ -24,6 +24,7 @@ def create_queued_command( command_id: str = "command-id", command_key: str = "command-key", command_type: str = "command-type", + intent: cmd.CommandIntent = cmd.CommandIntent.PROTOCOL, params: Optional[BaseModel] = None, ) -> cmd.Command: """Given command data, build a pending command model.""" @@ -36,6 +37,7 @@ def create_queued_command( createdAt=datetime(year=2021, month=1, day=1), status=cmd.CommandStatus.QUEUED, params=params or BaseModel(), + intent=intent, ), ) @@ -577,3 +579,27 @@ def create_prepare_to_aspirate_command(pipette_id: str) -> cmd.PrepareToAspirate params=params, result=result, ) + + +def create_reload_labware_command( + labware_id: str, + offset_id: Optional[str], +) -> cmd.ReloadLabware: + """Create a completed ReloadLabware command.""" + params = cmd.ReloadLabwareParams( + labwareId=labware_id, + ) + + result = cmd.ReloadLabwareResult( + labwareId=labware_id, + offsetId=offset_id, + ) + + return cmd.ReloadLabware( + id="command-id", + key="command-key", + status=cmd.CommandStatus.SUCCEEDED, + createdAt=datetime.now(), + params=params, + result=result, + ) diff --git a/api/tests/opentrons/protocol_engine/state/test_addressable_area_store.py b/api/tests/opentrons/protocol_engine/state/test_addressable_area_store.py index 63e9cea2925..8a79d31ce92 100644 --- a/api/tests/opentrons/protocol_engine/state/test_addressable_area_store.py +++ b/api/tests/opentrons/protocol_engine/state/test_addressable_area_store.py @@ -1,7 +1,7 @@ """Addressable area state store tests.""" import pytest -from opentrons_shared_data.deck.dev_types import DeckDefinitionV4 +from opentrons_shared_data.deck.dev_types import DeckDefinitionV5 from opentrons_shared_data.labware.labware_definition import Parameters from opentrons.protocols.models import LabwareDefinition from opentrons.types import DeckSlotName @@ -35,24 +35,24 @@ def _make_deck_config() -> DeckConfigurationType: return [ - ("cutoutA1", "singleLeftSlot"), - ("cutoutB1", "singleLeftSlot"), - ("cutoutC1", "singleLeftSlot"), - ("cutoutD1", "singleLeftSlot"), - ("cutoutA2", "singleCenterSlot"), - ("cutoutB2", "singleCenterSlot"), - ("cutoutC2", "singleCenterSlot"), - ("cutoutD2", "singleCenterSlot"), - ("cutoutA3", "trashBinAdapter"), - ("cutoutB3", "singleRightSlot"), - ("cutoutC3", "stagingAreaRightSlot"), - ("cutoutD3", "wasteChuteRightAdapterNoCover"), + ("cutoutA1", "singleLeftSlot", None), + ("cutoutB1", "singleLeftSlot", None), + ("cutoutC1", "singleLeftSlot", None), + ("cutoutD1", "singleLeftSlot", None), + ("cutoutA2", "singleCenterSlot", None), + ("cutoutB2", "singleCenterSlot", None), + ("cutoutC2", "singleCenterSlot", None), + ("cutoutD2", "singleCenterSlot", None), + ("cutoutA3", "trashBinAdapter", None), + ("cutoutB3", "singleRightSlot", None), + ("cutoutC3", "stagingAreaRightSlot", None), + ("cutoutD3", "wasteChuteRightAdapterNoCover", None), ] @pytest.fixture def simulated_subject( - ot3_standard_deck_def: DeckDefinitionV4, + ot3_standard_deck_def: DeckDefinitionV5, ) -> AddressableAreaStore: """Get an AddressableAreaStore test subject, under simulated deck conditions.""" return AddressableAreaStore( @@ -68,7 +68,7 @@ def simulated_subject( @pytest.fixture def subject( - ot3_standard_deck_def: DeckDefinitionV4, + ot3_standard_deck_def: DeckDefinitionV5, ) -> AddressableAreaStore: """Get an AddressableAreaStore test subject.""" return AddressableAreaStore( @@ -83,7 +83,7 @@ def subject( def test_initial_state_simulated( - ot3_standard_deck_def: DeckDefinitionV4, + ot3_standard_deck_def: DeckDefinitionV5, simulated_subject: AddressableAreaStore, ) -> None: """It should create the Addressable Area store with no loaded addressable areas.""" @@ -98,7 +98,7 @@ def test_initial_state_simulated( def test_initial_state( - ot3_standard_deck_def: DeckDefinitionV4, + ot3_standard_deck_def: DeckDefinitionV5, subject: AddressableAreaStore, ) -> None: """It should create the Addressable Area store with loaded addressable areas.""" diff --git a/api/tests/opentrons/protocol_engine/state/test_addressable_area_view.py b/api/tests/opentrons/protocol_engine/state/test_addressable_area_view.py index 34ddcaa37fa..e903c59a45d 100644 --- a/api/tests/opentrons/protocol_engine/state/test_addressable_area_view.py +++ b/api/tests/opentrons/protocol_engine/state/test_addressable_area_view.py @@ -6,7 +6,7 @@ from typing import Dict, Set, Optional, cast from opentrons_shared_data.robot.dev_types import RobotType -from opentrons_shared_data.deck.dev_types import DeckDefinitionV4 +from opentrons_shared_data.deck.dev_types import DeckDefinitionV5 from opentrons.types import Point, DeckSlotName from opentrons.protocol_engine.errors import ( @@ -47,7 +47,7 @@ def get_addressable_area_view( potential_cutout_fixtures_by_cutout_id: Optional[ Dict[str, Set[PotentialCutoutFixture]] ] = None, - deck_definition: Optional[DeckDefinitionV4] = None, + deck_definition: Optional[DeckDefinitionV5] = None, deck_configuration: Optional[DeckConfigurationType] = None, robot_type: RobotType = "OT-3 Standard", use_simulated_deck_config: bool = False, @@ -57,7 +57,7 @@ def get_addressable_area_view( loaded_addressable_areas_by_name=loaded_addressable_areas_by_name or {}, potential_cutout_fixtures_by_cutout_id=potential_cutout_fixtures_by_cutout_id or {}, - deck_definition=deck_definition or cast(DeckDefinitionV4, {"otId": "fake"}), + deck_definition=deck_definition or cast(DeckDefinitionV5, {"otId": "fake"}), deck_configuration=deck_configuration or [], robot_type=robot_type, use_simulated_deck_config=use_simulated_deck_config, @@ -79,8 +79,8 @@ def test_get_all_cutout_fixtures_non_simulated_deck_config() -> None: """It should return the cutout fixtures from the deck config, if it's not simulated.""" subject = get_addressable_area_view( deck_configuration=[ - ("cutout-id-1", "cutout-fixture-id-1"), - ("cutout-id-2", "cutout-fixture-id-2"), + ("cutout-id-1", "cutout-fixture-id-1", None), + ("cutout-id-2", "cutout-fixture-id-2", None), ], use_simulated_deck_config=False, ) @@ -309,6 +309,8 @@ def test_get_fixture_height(decoy: Decoy) -> None: "height": 10, # These values don't matter: "id": "id", + "expectOpentronsModuleSerialNumber": False, + "fixtureGroup": {}, "mayMountTo": [], "displayName": "", "providesAddressableAreas": {}, @@ -324,6 +326,8 @@ def test_get_fixture_height(decoy: Decoy) -> None: "height": 9000.1, # These values don't matter: "id": "id", + "expectOpentronsModuleSerialNumber": False, + "fixtureGroup": {}, "mayMountTo": [], "displayName": "", "providesAddressableAreas": {}, diff --git a/api/tests/opentrons/protocol_engine/state/test_change_notifier.py b/api/tests/opentrons/protocol_engine/state/test_change_notifier.py deleted file mode 100644 index 4967e6d254e..00000000000 --- a/api/tests/opentrons/protocol_engine/state/test_change_notifier.py +++ /dev/null @@ -1,56 +0,0 @@ -"""Tests for the ChangeNotifier interface.""" -import asyncio -import pytest -from opentrons.protocol_engine.state.change_notifier import ChangeNotifier - - -async def test_single_subscriber() -> None: - """Test that a single subscriber can wait for a notification.""" - subject = ChangeNotifier() - result = asyncio.create_task(subject.wait()) - - # ensure that the wait actually waits by delaying and - # checking that the task has not resolved - await asyncio.sleep(0.1) - assert result.done() is False - - asyncio.get_running_loop().call_soon(subject.notify) - - await result - - -@pytest.mark.parametrize("_test_repetition", range(10)) -async def test_multiple_subscribers(_test_repetition: int) -> None: - """Test that multiple subscribers can wait for a notification. - - This test checks that the subscribers are awoken in the order they - subscribed. This may or may not be guarenteed according to the - implementations of both ChangeNotifier and the event loop. - This test functions as a canary, given that our code may relies - on this ordering for determinism. - - This test runs multiple times to check for flakyness. - """ - subject = ChangeNotifier() - results = [] - - async def _do_task_1() -> None: - await subject.wait() - results.append(1) - - async def _do_task_2() -> None: - await subject.wait() - results.append(2) - - async def _do_task_3() -> None: - await subject.wait() - results.append(3) - - task_1 = asyncio.create_task(_do_task_1()) - task_2 = asyncio.create_task(_do_task_2()) - task_3 = asyncio.create_task(_do_task_3()) - - asyncio.get_running_loop().call_soon(subject.notify) - await asyncio.gather(task_1, task_2, task_3) - - assert results == [1, 2, 3] diff --git a/api/tests/opentrons/protocol_engine/state/test_command_history.py b/api/tests/opentrons/protocol_engine/state/test_command_history.py index c6344141281..3c84b86e07f 100644 --- a/api/tests/opentrons/protocol_engine/state/test_command_history.py +++ b/api/tests/opentrons/protocol_engine/state/test_command_history.py @@ -5,6 +5,7 @@ from opentrons.protocol_engine.errors.exceptions import CommandDoesNotExistError from opentrons.protocol_engine.state.command_history import CommandHistory, CommandEntry +from opentrons.protocol_engine.commands import CommandIntent, CommandStatus from .command_fixtures import ( create_queued_command, @@ -18,6 +19,15 @@ def create_queued_command_entry( return CommandEntry(create_queued_command(command_id=command_id), index) +def create_fixit_command_entry( + command_id: str = "command-id", index: int = 0 +) -> CommandEntry: + """Create a command entry for a fixit command.""" + return CommandEntry( + create_queued_command(command_id=command_id, intent=CommandIntent.FIXIT), index + ) + + @pytest.fixture def command_history() -> CommandHistory: """Instantiates a CommandHistory instance.""" @@ -161,6 +171,14 @@ def test_get_setup_queue_ids(command_history: CommandHistory) -> None: assert command_history.get_setup_queue_ids() == OrderedSet(["0", "1"]) +def test_get_fixit_queue_ids(command_history: CommandHistory) -> None: + """It should return the IDs of all commands in the setup queue.""" + assert command_history.get_fixit_queue_ids() == OrderedSet() + command_history._add_to_fixit_queue("0") + command_history._add_to_fixit_queue("1") + assert command_history.get_fixit_queue_ids() == OrderedSet(["0", "1"]) + + def test_set_command_entry(command_history: CommandHistory) -> None: """It should set the command entry for the given ID.""" command_entry = create_queued_command_entry() @@ -184,6 +202,41 @@ def test_set_running_command_id(command_history: CommandHistory) -> None: assert command_history.get_running_command() == command_entry +def test_set_fixit_running_command_id(command_history: CommandHistory) -> None: + """It should set the ID of the currently running fixit command.""" + command_entry = create_queued_command() + command_history.set_command_queued(command_entry) + running_command = command_entry.copy( + update={ + "status": CommandStatus.RUNNING, + } + ) + command_history.set_command_running(running_command) + finished_command = command_entry.copy( + update={ + "status": CommandStatus.SUCCEEDED, + } + ) + command_history.set_command_succeeded(finished_command) + fixit_command_entry = create_queued_command( + command_id="fixit-id", intent=CommandIntent.FIXIT + ) + command_history.set_command_queued(fixit_command_entry) + fixit_running_command = fixit_command_entry.copy( + update={ + "status": CommandStatus.RUNNING, + } + ) + command_history.set_command_running(fixit_running_command) + current_running_command = command_history.get_running_command() + assert current_running_command is not None + assert current_running_command.command == fixit_running_command + assert command_history.get_all_commands() == [ + finished_command, + fixit_running_command, + ] + + def test_add_to_queue(command_history: CommandHistory) -> None: """It should add the given ID to the queue.""" command_history._add_to_queue("0") @@ -196,6 +249,13 @@ def test_add_to_setup_queue(command_history: CommandHistory) -> None: assert command_history.get_setup_queue_ids() == OrderedSet(["0"]) +def test_add_to_fixit_queue(command_history: CommandHistory) -> None: + """It should add the given ID to the setup queue.""" + fixit_command = create_queued_command(intent=CommandIntent.FIXIT) + command_history.set_command_queued(fixit_command) + assert command_history.get_fixit_queue_ids() == OrderedSet(["command-id"]) + + def test_clear_queue(command_history: CommandHistory) -> None: """It should clear all commands in the queue.""" command_history._add_to_queue("0") @@ -212,6 +272,19 @@ def test_clear_setup_queue(command_history: CommandHistory) -> None: assert command_history.get_setup_queue_ids() == OrderedSet() +def test_clear_fixit_queue(command_history: CommandHistory) -> None: + """It should clear all commands in the setup queue.""" + command_history.set_command_queued( + create_queued_command(command_id="0", intent=CommandIntent.FIXIT) + ) + command_history.set_command_queued( + create_queued_command(command_id="1", intent=CommandIntent.FIXIT) + ) + assert command_history.get_fixit_queue_ids() == OrderedSet(["0", "1"]) + command_history.clear_fixit_queue() + assert command_history.get_fixit_queue_ids() == OrderedSet() + + def test_remove_id_from_queue(command_history: CommandHistory) -> None: """It should remove the given ID from the queue.""" command_history._add_to_queue("0") diff --git a/api/tests/opentrons/protocol_engine/state/test_command_state.py b/api/tests/opentrons/protocol_engine/state/test_command_state.py index 8f1ea39fc00..742abf3e6e9 100644 --- a/api/tests/opentrons/protocol_engine/state/test_command_state.py +++ b/api/tests/opentrons/protocol_engine/state/test_command_state.py @@ -5,6 +5,7 @@ """ from datetime import datetime +from unittest.mock import sentinel import pytest @@ -13,10 +14,15 @@ from opentrons.ordered_set import OrderedSet from opentrons.protocol_engine import actions, commands, errors from opentrons.protocol_engine.error_recovery_policy import ErrorRecoveryType +from opentrons.protocol_engine.errors.error_occurrence import ErrorOccurrence +from opentrons.protocol_engine.errors.exceptions import EStopActivatedError from opentrons.protocol_engine.notes.notes import CommandNote -from opentrons.protocol_engine.state.commands import CommandStore, CommandView +from opentrons.protocol_engine.state.commands import ( + CommandStore, + CommandView, +) from opentrons.protocol_engine.state.config import Config -from opentrons.protocol_engine.types import DeckType +from opentrons.protocol_engine.types import DeckType, EngineStatus def _make_config() -> Config: @@ -434,3 +440,32 @@ def test_get_recovery_in_progress_for_command() -> None: # c3 failed, but not recoverably. assert not subject_view.get_recovery_in_progress_for_command("c2") + + +def test_final_state_after_estop() -> None: + """Test the final state of the run after it's E-stopped.""" + subject = CommandStore(config=_make_config(), is_door_open=False) + subject_view = CommandView(subject.state) + + error_details = actions.FinishErrorDetails( + error=EStopActivatedError(), error_id="error-id", created_at=datetime.now() + ) + expected_error_occurrence = ErrorOccurrence( + id=error_details.error_id, + createdAt=error_details.created_at, + errorCode=ErrorCodes.E_STOP_ACTIVATED.value.code, + errorType="EStopActivatedError", + detail="E-stop activated.", + ) + + subject.handle_action(actions.StopAction(from_estop=True)) + subject.handle_action(actions.FinishAction(error_details=error_details)) + subject.handle_action( + actions.HardwareStoppedAction( + completed_at=sentinel.hardware_stopped_action_completed_at, + finish_error_details=None, + ) + ) + + assert subject_view.get_status() == EngineStatus.FAILED + assert subject_view.get_error() == expected_error_occurrence diff --git a/api/tests/opentrons/protocol_engine/state/test_command_store_old.py b/api/tests/opentrons/protocol_engine/state/test_command_store_old.py index a859ae7573b..7f376a0b019 100644 --- a/api/tests/opentrons/protocol_engine/state/test_command_store_old.py +++ b/api/tests/opentrons/protocol_engine/state/test_command_store_old.py @@ -84,7 +84,7 @@ def test_initial_state( failed_command=None, command_error_recovery_types={}, recovery_target_command_id=None, - latest_command_hash=None, + latest_protocol_command_hash=None, stopped_by_estop=False, ) @@ -254,7 +254,7 @@ def test_command_queue_with_hash() -> None: ) assert subject.state.command_history.get("command-id-1").command.key == "abc123" - assert subject.state.latest_command_hash == "abc123" + assert subject.state.latest_protocol_command_hash == "abc123" subject.handle_action( QueueCommandAction( @@ -265,7 +265,7 @@ def test_command_queue_with_hash() -> None: ) ) - assert subject.state.latest_command_hash == "def456" + assert subject.state.latest_protocol_command_hash == "def456" def test_command_queue_and_unqueue() -> None: @@ -518,7 +518,7 @@ def test_command_store_handles_pause_action(pause_source: PauseSource) -> None: failed_command=None, command_error_recovery_types={}, recovery_target_command_id=None, - latest_command_hash=None, + latest_protocol_command_hash=None, stopped_by_estop=False, ) @@ -545,7 +545,7 @@ def test_command_store_handles_play_action(pause_source: PauseSource) -> None: command_error_recovery_types={}, recovery_target_command_id=None, run_started_at=datetime(year=2021, month=1, day=1), - latest_command_hash=None, + latest_protocol_command_hash=None, stopped_by_estop=False, ) assert subject.state.command_history.get_running_command() is None @@ -577,7 +577,7 @@ def test_command_store_handles_finish_action() -> None: command_error_recovery_types={}, recovery_target_command_id=None, run_started_at=datetime(year=2021, month=1, day=1), - latest_command_hash=None, + latest_protocol_command_hash=None, stopped_by_estop=False, ) assert subject.state.command_history.get_running_command() is None @@ -600,8 +600,13 @@ def test_command_store_handles_finish_action_with_stopped() -> None: assert subject.state.run_result == RunResult.STOPPED -@pytest.mark.parametrize("from_estop", [True, False]) -def test_command_store_handles_stop_action(from_estop: bool) -> None: +@pytest.mark.parametrize( + ["from_estop", "expected_run_result"], + [(True, RunResult.FAILED), (False, RunResult.STOPPED)], +) +def test_command_store_handles_stop_action( + from_estop: bool, expected_run_result: RunResult +) -> None: """It should mark the engine as non-gracefully stopped on StopAction.""" subject = CommandStore(is_door_open=False, config=_make_config()) @@ -615,7 +620,7 @@ def test_command_store_handles_stop_action(from_estop: bool) -> None: assert subject.state == CommandState( command_history=CommandHistory(), queue_status=QueueStatus.PAUSED, - run_result=RunResult.STOPPED, + run_result=expected_run_result, run_completed_at=None, is_door_blocking=False, run_error=None, @@ -624,7 +629,7 @@ def test_command_store_handles_stop_action(from_estop: bool) -> None: command_error_recovery_types={}, recovery_target_command_id=None, run_started_at=datetime(year=2021, month=1, day=1), - latest_command_hash=None, + latest_protocol_command_hash=None, stopped_by_estop=from_estop, ) assert subject.state.command_history.get_running_command() is None @@ -633,6 +638,41 @@ def test_command_store_handles_stop_action(from_estop: bool) -> None: assert subject.state.command_history.get_setup_queue_ids() == OrderedSet() +def test_command_store_handles_stop_action_when_awaiting_recovery() -> None: + """It should mark the engine as non-gracefully stopped on StopAction.""" + subject = CommandStore(is_door_open=False, config=_make_config()) + + subject.handle_action( + PlayAction( + requested_at=datetime(year=2021, month=1, day=1), deck_configuration=[] + ) + ) + + subject.state.queue_status = QueueStatus.AWAITING_RECOVERY + + subject.handle_action(StopAction()) + + assert subject.state == CommandState( + command_history=CommandHistory(), + queue_status=QueueStatus.PAUSED, + run_result=RunResult.STOPPED, + run_completed_at=None, + is_door_blocking=False, + run_error=None, + finish_error=None, + failed_command=None, + command_error_recovery_types={}, + recovery_target_command_id=None, + run_started_at=datetime(year=2021, month=1, day=1), + latest_protocol_command_hash=None, + stopped_by_estop=False, + ) + assert subject.state.command_history.get_running_command() is None + assert subject.state.command_history.get_all_ids() == [] + assert subject.state.command_history.get_queue_ids() == OrderedSet() + assert subject.state.command_history.get_setup_queue_ids() == OrderedSet() + + def test_command_store_cannot_restart_after_should_stop() -> None: """It should reject a play action after finish.""" subject = CommandStore(is_door_open=False, config=_make_config()) @@ -655,7 +695,7 @@ def test_command_store_cannot_restart_after_should_stop() -> None: command_error_recovery_types={}, recovery_target_command_id=None, run_started_at=None, - latest_command_hash=None, + latest_protocol_command_hash=None, stopped_by_estop=False, ) assert subject.state.command_history.get_running_command() is None @@ -787,7 +827,7 @@ def test_command_store_wraps_unknown_errors() -> None: failed_command=None, command_error_recovery_types={}, recovery_target_command_id=None, - latest_command_hash=None, + latest_protocol_command_hash=None, stopped_by_estop=False, ) assert subject.state.command_history.get_running_command() is None @@ -850,7 +890,7 @@ def __init__(self, message: str) -> None: command_error_recovery_types={}, recovery_target_command_id=None, run_started_at=None, - latest_command_hash=None, + latest_protocol_command_hash=None, stopped_by_estop=False, ) assert subject.state.command_history.get_running_command() is None @@ -883,7 +923,7 @@ def test_command_store_ignores_stop_after_graceful_finish() -> None: command_error_recovery_types={}, recovery_target_command_id=None, run_started_at=datetime(year=2021, month=1, day=1), - latest_command_hash=None, + latest_protocol_command_hash=None, stopped_by_estop=False, ) assert subject.state.command_history.get_running_command() is None @@ -916,7 +956,7 @@ def test_command_store_ignores_finish_after_non_graceful_stop() -> None: command_error_recovery_types={}, recovery_target_command_id=None, run_started_at=datetime(year=2021, month=1, day=1), - latest_command_hash=None, + latest_protocol_command_hash=None, stopped_by_estop=False, ) assert subject.state.command_history.get_running_command() is None @@ -945,7 +985,7 @@ def test_handles_hardware_stopped() -> None: command_error_recovery_types={}, recovery_target_command_id=None, run_started_at=None, - latest_command_hash=None, + latest_protocol_command_hash=None, stopped_by_estop=False, ) assert subject.state.command_history.get_running_command() is None diff --git a/api/tests/opentrons/protocol_engine/state/test_command_view_old.py b/api/tests/opentrons/protocol_engine/state/test_command_view_old.py index a9b5fc92cc3..19a2515a3e6 100644 --- a/api/tests/opentrons/protocol_engine/state/test_command_view_old.py +++ b/api/tests/opentrons/protocol_engine/state/test_command_view_old.py @@ -46,7 +46,7 @@ ) -def get_command_view( +def get_command_view( # noqa: C901 queue_status: QueueStatus = QueueStatus.SETUP, run_completed_at: Optional[datetime] = None, run_started_at: Optional[datetime] = None, @@ -55,6 +55,7 @@ def get_command_view( running_command_id: Optional[str] = None, queued_command_ids: Sequence[str] = (), queued_setup_command_ids: Sequence[str] = (), + queued_fixit_command_ids: Sequence[str] = (), run_error: Optional[errors.ErrorOccurrence] = None, failed_command: Optional[CommandEntry] = None, command_error_recovery_types: Optional[Dict[str, ErrorRecoveryType]] = None, @@ -74,6 +75,9 @@ def get_command_view( if queued_setup_command_ids: for command_id in queued_setup_command_ids: command_history._add_to_setup_queue(command_id) + if queued_fixit_command_ids: + for command_id in queued_fixit_command_ids: + command_history._add_to_fixit_queue(command_id) if commands: for index, command in enumerate(commands): command_history._add( @@ -93,7 +97,7 @@ def get_command_view( command_error_recovery_types=command_error_recovery_types or {}, recovery_target_command_id=recovery_target_command_id, run_started_at=run_started_at, - latest_command_hash=latest_command_hash, + latest_protocol_command_hash=latest_command_hash, stopped_by_estop=False, ) @@ -133,6 +137,7 @@ def test_get_next_to_execute_returns_first_queued() -> None: subject = get_command_view( queue_status=QueueStatus.RUNNING, queued_command_ids=["command-id-1", "command-id-2"], + queued_fixit_command_ids=["fixit-id-1", "fixit-id-2"], ) assert subject.get_next_to_execute() == "command-id-1" @@ -155,6 +160,24 @@ def test_get_next_to_execute_prioritizes_setup_command_queue( assert subject.get_next_to_execute() == "setup-command-id" +@pytest.mark.parametrize( + "queue_status", + [QueueStatus.AWAITING_RECOVERY], +) +def test_get_next_to_execute_prioritizes_fixit_command_queue( + queue_status: QueueStatus, +) -> None: + """It should prioritize fixit command queue over protocol command queue.""" + subject = get_command_view( + queue_status=queue_status, + queued_command_ids=["command-id-1", "command-id-2"], + queued_setup_command_ids=["setup-command-id"], + queued_fixit_command_ids=["fixit-1", "fixit-2"], + ) + + assert subject.get_next_to_execute() == "fixit-1" + + def test_get_next_to_execute_returns_none_when_no_queued() -> None: """It should return None if there are no queued commands.""" subject = get_command_view( @@ -186,6 +209,20 @@ def test_get_next_to_execute_returns_no_commands_if_paused() -> None: queue_status=QueueStatus.PAUSED, queued_setup_command_ids=["setup-id-1", "setup-id-2"], queued_command_ids=["command-id-1", "command-id-2"], + queued_fixit_command_ids=["fixit-id-1", "fixit-id-2"], + ) + result = subject.get_next_to_execute() + + assert result is None + + +def test_get_next_to_execute_returns_no_commands_if_awaiting_recovery_no_fixit() -> None: + """It should not return any type of command if the engine is awaiting-recovery.""" + subject = get_command_view( + queue_status=QueueStatus.AWAITING_RECOVERY, + queued_setup_command_ids=["setup-id-1", "setup-id-2"], + queued_command_ids=["command-id-1", "command-id-2"], + queued_fixit_command_ids=[], ) result = subject.get_next_to_execute() @@ -486,12 +523,69 @@ class ActionAllowedSpec(NamedTuple): ), expected_error=errors.SetupCommandNotAllowedError, ), - # Resuming from error recovery is not implemented yet. - # https://opentrons.atlassian.net/browse/EXEC-301 + # fixit command is disallowed if not in recovery mode ActionAllowedSpec( - subject=get_command_view(), + subject=get_command_view(queue_status=QueueStatus.RUNNING), + action=QueueCommandAction( + request=cmd.HomeCreate( + params=cmd.HomeParams(), + intent=cmd.CommandIntent.FIXIT, + ), + request_hash=None, + command_id="command-id", + created_at=datetime(year=2021, month=1, day=1), + ), + expected_error=errors.FixitCommandNotAllowedError, + ), + ActionAllowedSpec( + subject=get_command_view( + queue_status=QueueStatus.AWAITING_RECOVERY, + failed_command=CommandEntry( + index=2, + command=create_failed_command( + command_id="command-id-3", + error=ErrorOccurrence( + id="error-id", + errorType="ProtocolEngineError", + createdAt=datetime(year=2022, month=2, day=2), + detail="oh no", + errorCode=ErrorCodes.GENERAL_ERROR.value.code, + ), + ), + ), + ), + action=QueueCommandAction( + request=cmd.HomeCreate( + params=cmd.HomeParams(), + intent=cmd.CommandIntent.FIXIT, + ), + request_hash=None, + command_id="command-id", + created_at=datetime(year=2021, month=1, day=1), + ), + expected_error=None, + ), + # resume from recovery not allowed if fixit commands in queue + ActionAllowedSpec( + subject=get_command_view( + queue_status=QueueStatus.AWAITING_RECOVERY, + queued_fixit_command_ids=["fixit-id-1", "fixit-id-2"], + failed_command=CommandEntry( + index=2, + command=create_failed_command( + command_id="command-id-3", + error=ErrorOccurrence( + id="error-id", + errorType="ProtocolEngineError", + createdAt=datetime(year=2022, month=2, day=2), + detail="oh no", + errorCode=ErrorCodes.GENERAL_ERROR.value.code, + ), + ), + ), + ), action=ResumeFromRecoveryAction(), - expected_error=NotImplementedError, + expected_error=errors.ResumeFromRecoveryNotAllowedError, ), ] @@ -931,4 +1025,4 @@ def test_get_slice_default_cursor_queued() -> None: def test_get_latest_command_hash() -> None: """It should get the latest command hash from state, if set.""" subject = get_command_view(latest_command_hash="abc123") - assert subject.get_latest_command_hash() == "abc123" + assert subject.get_latest_protocol_command_hash() == "abc123" diff --git a/api/tests/opentrons/protocol_engine/state/test_geometry_view.py b/api/tests/opentrons/protocol_engine/state/test_geometry_view.py index 731bcfb9a0e..82cf971595e 100644 --- a/api/tests/opentrons/protocol_engine/state/test_geometry_view.py +++ b/api/tests/opentrons/protocol_engine/state/test_geometry_view.py @@ -1,11 +1,14 @@ """Test state getters for retrieving geometry views of state.""" import inspect +import json import pytest from decoy import Decoy from typing import cast, List, Tuple, Optional, NamedTuple +from datetime import datetime -from opentrons_shared_data.deck.dev_types import DeckDefinitionV4 +from opentrons_shared_data.deck.dev_types import DeckDefinitionV5 +from opentrons_shared_data.deck import load as load_deck from opentrons_shared_data.labware.dev_types import LabwareUri from opentrons_shared_data.pipette import pipette_definition from opentrons.calibration_storage.helpers import uri_from_details @@ -17,6 +20,7 @@ Parameters as LabwareDefinitionParameters, CornerOffsetFromSlot, ) +from opentrons_shared_data import load_shared_data from opentrons.protocol_engine import errors from opentrons.protocol_engine.types import ( @@ -45,30 +49,45 @@ LabwareMovementOffsetData, LoadedPipette, TipGeometry, + ModuleDefinition, ) +from opentrons.protocol_engine.commands import ( + CommandStatus, + LoadLabwareResult, + LoadLabware, + LoadLabwareParams, + LoadModuleResult, + LoadModule, + LoadModuleParams, +) +from opentrons.protocol_engine.actions import SucceedCommandAction from opentrons.protocol_engine.state import move_types from opentrons.protocol_engine.state.config import Config -from opentrons.protocol_engine.state.labware import LabwareView -from opentrons.protocol_engine.state.modules import ModuleView +from opentrons.protocol_engine.state.labware import LabwareView, LabwareStore +from opentrons.protocol_engine.state.modules import ModuleView, ModuleStore from opentrons.protocol_engine.state.pipettes import ( PipetteView, + PipetteStore, StaticPipetteConfig, BoundingNozzlesOffsets, PipetteBoundingBoxOffsets, ) -from opentrons.protocol_engine.state.addressable_areas import AddressableAreaView +from opentrons.protocol_engine.state.addressable_areas import ( + AddressableAreaView, + AddressableAreaStore, +) from opentrons.protocol_engine.state.geometry import GeometryView, _GripperMoveType from ..pipette_fixtures import get_default_nozzle_map @pytest.fixture -def labware_view(decoy: Decoy) -> LabwareView: +def mock_labware_view(decoy: Decoy) -> LabwareView: """Get a mock in the shape of a LabwareView.""" return decoy.mock(cls=LabwareView) @pytest.fixture -def module_view(decoy: Decoy) -> ModuleView: +def mock_module_view(decoy: Decoy) -> ModuleView: """Get a mock in the shape of a ModuleView.""" return decoy.mock(cls=ModuleView) @@ -80,7 +99,7 @@ def mock_pipette_view(decoy: Decoy) -> PipetteView: @pytest.fixture -def addressable_area_view(decoy: Decoy) -> AddressableAreaView: +def mock_addressable_area_view(decoy: Decoy) -> AddressableAreaView: """Get a mock in the shape of a AddressableAreaView.""" return decoy.mock(cls=AddressableAreaView) @@ -92,30 +111,145 @@ def patch_mock_move_types(decoy: Decoy, monkeypatch: pytest.MonkeyPatch) -> None monkeypatch.setattr(move_types, name, decoy.mock(func=func)) +@pytest.fixture +def use_mocks() -> bool: + """True to use mocks; add a use_mocks parameter of False to your test to use real states.""" + return True + + +@pytest.fixture +def deck_definition(state_config: Config) -> DeckDefinitionV5: + """Override as parameter to use a non-flex deck def.""" + return load_deck(name=state_config.deck_type.value, version=5) + + +@pytest.fixture +def state_config() -> Config: + """Get a state config. This is set up for a Flex.""" + return Config( + robot_type="OT-3 Standard", + deck_type=DeckType.OT3_STANDARD, + ) + + +@pytest.fixture +def labware_store(deck_definition: DeckDefinitionV5) -> LabwareStore: + """Get a labware store that can accept actions.""" + return LabwareStore(deck_definition=deck_definition, deck_fixed_labware=[]) + + +@pytest.fixture +def labware_view(labware_store: LabwareStore) -> LabwareView: + """Get a labware view of a real labware store.""" + return LabwareView(labware_store._state) + + +@pytest.fixture +def module_store(state_config: Config) -> ModuleStore: + """Get a module store that can accept actions.""" + return ModuleStore(config=state_config, module_calibration_offsets={}) + + +@pytest.fixture +def module_view(module_store: ModuleStore) -> ModuleView: + """Get a module view of a real labware store.""" + return ModuleView(module_store._state) + + +@pytest.fixture +def pipette_store() -> PipetteStore: + """Get a pipette store that can accept actions.""" + return PipetteStore() + + +@pytest.fixture +def pipette_view(pipette_store: PipetteStore) -> PipetteView: + """Get a pipette view of a real pipette store.""" + return PipetteView(pipette_store._state) + + +@pytest.fixture +def addressable_area_store( + state_config: Config, deck_definition: DeckDefinitionV5 +) -> AddressableAreaStore: + """Get an addressable area store that can accept actions.""" + return AddressableAreaStore( + deck_configuration=[], config=state_config, deck_definition=deck_definition + ) + + +@pytest.fixture +def addressable_area_view( + addressable_area_store: AddressableAreaStore, +) -> AddressableAreaView: + """Get an addressable area view of a real addressable are store.""" + return AddressableAreaView(addressable_area_store._state) + + +@pytest.fixture +def nice_labware_definition() -> LabwareDefinition: + """Load a nice labware def that won't blow up your terminal.""" + return LabwareDefinition.parse_obj( + json.loads( + load_shared_data("labware/fixtures/2/fixture_12_trough_v2.json").decode( + "utf-8" + ) + ) + ) + + +@pytest.fixture +def nice_adapter_definition() -> LabwareDefinition: + """Load a friendly adapter definition.""" + return LabwareDefinition.parse_obj( + json.loads( + load_shared_data( + "labware/definitions/2/opentrons_aluminum_flat_bottom_plate/1.json" + ).decode("utf-8") + ) + ) + + @pytest.fixture def subject( + mock_labware_view: LabwareView, + mock_module_view: ModuleView, + mock_pipette_view: PipetteView, + mock_addressable_area_view: AddressableAreaView, + state_config: Config, labware_view: LabwareView, module_view: ModuleView, - mock_pipette_view: PipetteView, + pipette_view: PipetteView, addressable_area_view: AddressableAreaView, + use_mocks: bool, ) -> GeometryView: - """Get a GeometryView with its store dependencies mocked out.""" + """Get a GeometryView with its store dependencies provided. + + By default, this will return a view with those dependencies as mocked. If you add a + parameter to your test of use_mocks that returns false, i.e. + + @pytest.mark.parametrize('use_mocks', [False]) + def my_cool_test(subject: GeometryView) -> None: + pass + + then the provided subject will use actual states. Over time, we should get more and more + things using use_mocks=True, and then flip the default + """ return GeometryView( - config=Config( - robot_type="OT-3 Standard", - deck_type=DeckType.OT3_STANDARD, - ), - labware_view=labware_view, - module_view=module_view, - pipette_view=mock_pipette_view, - addressable_area_view=addressable_area_view, + config=state_config, + labware_view=mock_labware_view if use_mocks else labware_view, + module_view=mock_module_view if use_mocks else module_view, + pipette_view=mock_pipette_view if use_mocks else pipette_view, + addressable_area_view=mock_addressable_area_view + if use_mocks + else addressable_area_view, ) def test_get_labware_parent_position( decoy: Decoy, - labware_view: LabwareView, - addressable_area_view: AddressableAreaView, + mock_labware_view: LabwareView, + mock_addressable_area_view: AddressableAreaView, subject: GeometryView, ) -> None: """It should return a deck slot position for labware in a deck slot.""" @@ -126,9 +260,9 @@ def test_get_labware_parent_position( location=DeckSlotLocation(slotName=DeckSlotName.SLOT_3), offsetId=None, ) - decoy.when(labware_view.get("labware-id")).then_return(labware_data) + decoy.when(mock_labware_view.get("labware-id")).then_return(labware_data) decoy.when( - addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) + mock_addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) ).then_return(Point(1, 2, 3)) result = subject.get_labware_parent_position("labware-id") @@ -138,7 +272,7 @@ def test_get_labware_parent_position( def test_raise_error_for_off_deck_labware_parent( decoy: Decoy, - labware_view: LabwareView, + mock_labware_view: LabwareView, subject: GeometryView, ) -> None: """Test raise error when fetching parent for labware that's off-deck.""" @@ -149,17 +283,17 @@ def test_raise_error_for_off_deck_labware_parent( location=OFF_DECK_LOCATION, offsetId=None, ) - decoy.when(labware_view.get("labware-id")).then_return(labware_data) + decoy.when(mock_labware_view.get("labware-id")).then_return(labware_data) with pytest.raises(errors.LabwareNotOnDeckError): subject.get_labware_parent_position("labware-id") def test_get_labware_parent_position_on_module( decoy: Decoy, - labware_view: LabwareView, - module_view: ModuleView, - addressable_area_view: AddressableAreaView, - ot2_standard_deck_def: DeckDefinitionV4, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, + mock_addressable_area_view: AddressableAreaView, + ot2_standard_deck_def: DeckDefinitionV5, subject: GeometryView, ) -> None: """It should return a module position for labware on a module.""" @@ -171,26 +305,34 @@ def test_get_labware_parent_position_on_module( offsetId=None, ) - decoy.when(labware_view.get("labware-id")).then_return(labware_data) - decoy.when(module_view.get_location("module-id")).then_return( + decoy.when(mock_labware_view.get("labware-id")).then_return(labware_data) + decoy.when(mock_module_view.get_location("module-id")).then_return( DeckSlotLocation(slotName=DeckSlotName.SLOT_3) ) decoy.when( - addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) + mock_addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) ).then_return(Point(1, 2, 3)) - decoy.when(labware_view.get_deck_definition()).then_return(ot2_standard_deck_def) + + decoy.when(mock_labware_view.get_deck_definition()).then_return( + ot2_standard_deck_def + ) + decoy.when( - module_view.get_nominal_module_offset(module_id="module-id") + mock_module_view.get_nominal_module_offset( + module_id="module-id", + addressable_areas=mock_addressable_area_view, + ) ).then_return(LabwareOffsetVector(x=4, y=5, z=6)) - decoy.when(module_view.get_connected_model("module-id")).then_return( + + decoy.when(mock_module_view.get_connected_model("module-id")).then_return( ModuleModel.THERMOCYCLER_MODULE_V2 ) decoy.when( - labware_view.get_module_overlap_offsets( + mock_labware_view.get_module_overlap_offsets( "labware-id", ModuleModel.THERMOCYCLER_MODULE_V2 ) ).then_return(OverlapOffset(x=1, y=2, z=3)) - decoy.when(module_view.get_module_calibration_offset("module-id")).then_return( + decoy.when(mock_module_view.get_module_calibration_offset("module-id")).then_return( ModuleOffsetData( moduleOffsetVector=ModuleOffsetVector(x=2, y=3, z=4), location=DeckSlotLocation(slotName=DeckSlotName.SLOT_3), @@ -204,10 +346,10 @@ def test_get_labware_parent_position_on_module( def test_get_labware_parent_position_on_labware( decoy: Decoy, - labware_view: LabwareView, - module_view: ModuleView, - addressable_area_view: AddressableAreaView, - ot2_standard_deck_def: DeckDefinitionV4, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, + mock_addressable_area_view: AddressableAreaView, + ot2_standard_deck_def: DeckDefinitionV5, subject: GeometryView, ) -> None: """It should return a labware position for labware on a labware on a module.""" @@ -225,36 +367,41 @@ def test_get_labware_parent_position_on_labware( location=ModuleLocation(moduleId="module-id"), offsetId=None, ) - decoy.when(labware_view.get("labware-id")).then_return(labware_data) - decoy.when(module_view.get_location("module-id")).then_return( + decoy.when(mock_labware_view.get("labware-id")).then_return(labware_data) + decoy.when(mock_module_view.get_location("module-id")).then_return( DeckSlotLocation(slotName=DeckSlotName.SLOT_3) ) decoy.when( - addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) + mock_addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) ).then_return(Point(1, 2, 3)) - decoy.when(labware_view.get("adapter-id")).then_return(adapter_data) - decoy.when(labware_view.get_dimensions("adapter-id")).then_return( + decoy.when(mock_labware_view.get("adapter-id")).then_return(adapter_data) + decoy.when(mock_labware_view.get_dimensions("adapter-id")).then_return( Dimensions(x=123, y=456, z=5) ) decoy.when( - labware_view.get_labware_overlap_offsets("labware-id", "xyz") + mock_labware_view.get_labware_overlap_offsets("labware-id", "xyz") ).then_return(OverlapOffset(x=1, y=2, z=2)) - decoy.when(labware_view.get_deck_definition()).then_return(ot2_standard_deck_def) + decoy.when(mock_labware_view.get_deck_definition()).then_return( + ot2_standard_deck_def + ) decoy.when( - module_view.get_nominal_module_offset(module_id="module-id") + mock_module_view.get_nominal_module_offset( + module_id="module-id", + addressable_areas=mock_addressable_area_view, + ) ).then_return(LabwareOffsetVector(x=1, y=2, z=3)) - decoy.when(module_view.get_connected_model("module-id")).then_return( + decoy.when(mock_module_view.get_connected_model("module-id")).then_return( ModuleModel.MAGNETIC_MODULE_V2 ) decoy.when( - labware_view.get_module_overlap_offsets( + mock_labware_view.get_module_overlap_offsets( "adapter-id", ModuleModel.MAGNETIC_MODULE_V2 ) ).then_return(OverlapOffset(x=-3, y=-2, z=-1)) - decoy.when(module_view.get_module_calibration_offset("module-id")).then_return( + decoy.when(mock_module_view.get_module_calibration_offset("module-id")).then_return( ModuleOffsetData( moduleOffsetVector=ModuleOffsetVector(x=3, y=4, z=5), location=DeckSlotLocation(slotName=DeckSlotName.SLOT_3), @@ -268,9 +415,9 @@ def test_get_labware_parent_position_on_labware( def test_module_calibration_offset_rotation( decoy: Decoy, - labware_view: LabwareView, - module_view: ModuleView, - ot2_standard_deck_def: DeckDefinitionV4, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, + ot2_standard_deck_def: DeckDefinitionV5, subject: GeometryView, ) -> None: """Return the rotated module calibration offset if the module was moved from one side of the deck to the other.""" @@ -282,14 +429,14 @@ def test_module_calibration_offset_rotation( offsetId=None, ) - decoy.when(labware_view.get("labware-id")).then_return(labware_data) - decoy.when(module_view.get_location("module-id")).then_return( + decoy.when(mock_labware_view.get("labware-id")).then_return(labware_data) + decoy.when(mock_module_view.get_location("module-id")).then_return( DeckSlotLocation(slotName=DeckSlotName.SLOT_D1) ) - decoy.when(module_view.get_connected_model("module-id")).then_return( + decoy.when(mock_module_view.get_connected_model("module-id")).then_return( ModuleModel.TEMPERATURE_MODULE_V2 ) - decoy.when(module_view.get_module_calibration_offset("module-id")).then_return( + decoy.when(mock_module_view.get_module_calibration_offset("module-id")).then_return( ModuleOffsetData( moduleOffsetVector=ModuleOffsetVector(x=2, y=3, z=4), location=DeckSlotLocation(slotName=DeckSlotName.SLOT_D1), @@ -301,7 +448,7 @@ def test_module_calibration_offset_rotation( assert result == ModuleOffsetVector(x=2, y=3, z=4) # the module has changed from slot D1 to D3, so we should rotate the calibration offset 180 degrees along the z axis - decoy.when(module_view.get_location("module-id")).then_return( + decoy.when(mock_module_view.get_location("module-id")).then_return( DeckSlotLocation(slotName=DeckSlotName.SLOT_D3) ) result = subject._get_calibrated_module_offset(ModuleLocation(moduleId="module-id")) @@ -310,7 +457,7 @@ def test_module_calibration_offset_rotation( # attempting to load the module calibration offset from an invalid slot in the middle of the deck (A2, B2, C2, D2) # is not be allowed since you can't even load a module in the middle to perform a module calibration in the # first place. So if someone manually edits the stored module calibration offset we will throw an assert error. - decoy.when(module_view.get_module_calibration_offset("module-id")).then_return( + decoy.when(mock_module_view.get_module_calibration_offset("module-id")).then_return( ModuleOffsetData( moduleOffsetVector=ModuleOffsetVector(x=2, y=3, z=4), location=DeckSlotLocation(slotName=DeckSlotName.SLOT_D2), @@ -325,8 +472,8 @@ def test_module_calibration_offset_rotation( def test_get_labware_origin_position( decoy: Decoy, well_plate_def: LabwareDefinition, - labware_view: LabwareView, - addressable_area_view: AddressableAreaView, + mock_labware_view: LabwareView, + mock_addressable_area_view: AddressableAreaView, subject: GeometryView, ) -> None: """It should return a deck slot position with the labware's offset as its origin.""" @@ -338,10 +485,12 @@ def test_get_labware_origin_position( offsetId=None, ) - decoy.when(labware_view.get("labware-id")).then_return(labware_data) - decoy.when(labware_view.get_definition("labware-id")).then_return(well_plate_def) + decoy.when(mock_labware_view.get("labware-id")).then_return(labware_data) + decoy.when(mock_labware_view.get_definition("labware-id")).then_return( + well_plate_def + ) decoy.when( - addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) + mock_addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) ).then_return(Point(1, 2, 3)) expected_parent = Point(1, 2, 3) @@ -360,8 +509,8 @@ def test_get_labware_origin_position( def test_get_labware_highest_z( decoy: Decoy, well_plate_def: LabwareDefinition, - labware_view: LabwareView, - addressable_area_view: AddressableAreaView, + mock_labware_view: LabwareView, + mock_addressable_area_view: AddressableAreaView, subject: GeometryView, ) -> None: """It should get the absolute location of a labware's highest Z point.""" @@ -375,13 +524,15 @@ def test_get_labware_highest_z( slot_pos = Point(1, 2, 3) calibration_offset = LabwareOffsetVector(x=1, y=-2, z=3) - decoy.when(labware_view.get("labware-id")).then_return(labware_data) - decoy.when(labware_view.get_definition("labware-id")).then_return(well_plate_def) - decoy.when(labware_view.get_labware_offset_vector("labware-id")).then_return( + decoy.when(mock_labware_view.get("labware-id")).then_return(labware_data) + decoy.when(mock_labware_view.get_definition("labware-id")).then_return( + well_plate_def + ) + decoy.when(mock_labware_view.get_labware_offset_vector("labware-id")).then_return( calibration_offset ) decoy.when( - addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) + mock_addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) ).then_return(slot_pos) highest_z = subject.get_labware_highest_z("labware-id") @@ -392,10 +543,10 @@ def test_get_labware_highest_z( def test_get_module_labware_highest_z( decoy: Decoy, well_plate_def: LabwareDefinition, - labware_view: LabwareView, - module_view: ModuleView, - addressable_area_view: AddressableAreaView, - ot2_standard_deck_def: DeckDefinitionV4, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, + mock_addressable_area_view: AddressableAreaView, + ot2_standard_deck_def: DeckDefinitionV5, subject: GeometryView, ) -> None: """It should get the absolute location of a labware's highest Z point.""" @@ -409,33 +560,40 @@ def test_get_module_labware_highest_z( slot_pos = Point(1, 2, 3) calibration_offset = LabwareOffsetVector(x=1, y=-2, z=3) - decoy.when(labware_view.get("labware-id")).then_return(labware_data) - decoy.when(labware_view.get_definition("labware-id")).then_return(well_plate_def) - decoy.when(labware_view.get_labware_offset_vector("labware-id")).then_return( + decoy.when(mock_labware_view.get("labware-id")).then_return(labware_data) + decoy.when(mock_labware_view.get_definition("labware-id")).then_return( + well_plate_def + ) + decoy.when(mock_labware_view.get_labware_offset_vector("labware-id")).then_return( calibration_offset ) decoy.when( - addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) + mock_addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) ).then_return(slot_pos) - decoy.when(module_view.get_location("module-id")).then_return( + decoy.when(mock_module_view.get_location("module-id")).then_return( DeckSlotLocation(slotName=DeckSlotName.SLOT_3) ) - decoy.when(labware_view.get_deck_definition()).then_return(ot2_standard_deck_def) + decoy.when(mock_labware_view.get_deck_definition()).then_return( + ot2_standard_deck_def + ) decoy.when( - module_view.get_nominal_module_offset(module_id="module-id") + mock_module_view.get_nominal_module_offset( + module_id="module-id", + addressable_areas=mock_addressable_area_view, + ) ).then_return(LabwareOffsetVector(x=4, y=5, z=6)) - decoy.when(module_view.get_height_over_labware("module-id")).then_return(0.5) - decoy.when(module_view.get_module_calibration_offset("module-id")).then_return( + decoy.when(mock_module_view.get_height_over_labware("module-id")).then_return(0.5) + decoy.when(mock_module_view.get_module_calibration_offset("module-id")).then_return( ModuleOffsetData( moduleOffsetVector=ModuleOffsetVector(x=0, y=0, z=0), location=DeckSlotLocation(slotName=DeckSlotName.SLOT_3), ) ) - decoy.when(module_view.get_connected_model("module-id")).then_return( + decoy.when(mock_module_view.get_connected_model("module-id")).then_return( ModuleModel.MAGNETIC_MODULE_V2 ) decoy.when( - labware_view.get_module_overlap_offsets( + mock_labware_view.get_module_overlap_offsets( "labware-id", ModuleModel.MAGNETIC_MODULE_V2 ) ).then_return(OverlapOffset(x=0, y=0, z=0)) @@ -447,15 +605,15 @@ def test_get_module_labware_highest_z( def test_get_all_obstacle_highest_z_no_equipment( decoy: Decoy, - labware_view: LabwareView, - module_view: ModuleView, - addressable_area_view: AddressableAreaView, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, + mock_addressable_area_view: AddressableAreaView, subject: GeometryView, ) -> None: """It should return 0 if no loaded equipment.""" - decoy.when(module_view.get_all()).then_return([]) - decoy.when(labware_view.get_all()).then_return([]) - decoy.when(addressable_area_view.get_all()).then_return([]) + decoy.when(mock_module_view.get_all()).then_return([]) + decoy.when(mock_labware_view.get_all()).then_return([]) + decoy.when(mock_addressable_area_view.get_all()).then_return([]) result = subject.get_all_obstacle_highest_z() @@ -467,9 +625,9 @@ def test_get_all_obstacle_highest_z( well_plate_def: LabwareDefinition, reservoir_def: LabwareDefinition, falcon_tuberack_def: LabwareDefinition, - labware_view: LabwareView, - module_view: ModuleView, - addressable_area_view: AddressableAreaView, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, + mock_addressable_area_view: AddressableAreaView, subject: GeometryView, ) -> None: """It should get the highest Z amongst all labware.""" @@ -499,35 +657,37 @@ def test_get_all_obstacle_highest_z( off_deck_lw_offset = LabwareOffsetVector(x=1, y=-2, z=3) reservoir_offset = LabwareOffsetVector(x=1, y=-2, z=3) - decoy.when(module_view.get_all()).then_return([]) - decoy.when(addressable_area_view.get_all()).then_return([]) + decoy.when(mock_module_view.get_all()).then_return([]) + decoy.when(mock_addressable_area_view.get_all()).then_return([]) - decoy.when(labware_view.get_all()).then_return([plate, off_deck_lw, reservoir]) - decoy.when(labware_view.get("plate-id")).then_return(plate) - decoy.when(labware_view.get("off-deck-plate-id")).then_return(off_deck_lw) - decoy.when(labware_view.get("reservoir-id")).then_return(reservoir) + decoy.when(mock_labware_view.get_all()).then_return([plate, off_deck_lw, reservoir]) + decoy.when(mock_labware_view.get("plate-id")).then_return(plate) + decoy.when(mock_labware_view.get("off-deck-plate-id")).then_return(off_deck_lw) + decoy.when(mock_labware_view.get("reservoir-id")).then_return(reservoir) - decoy.when(labware_view.get_definition("plate-id")).then_return(well_plate_def) - decoy.when(labware_view.get_definition("off-deck-plate-id")).then_return( + decoy.when(mock_labware_view.get_definition("plate-id")).then_return(well_plate_def) + decoy.when(mock_labware_view.get_definition("off-deck-plate-id")).then_return( falcon_tuberack_def # Something tall. ) - decoy.when(labware_view.get_definition("reservoir-id")).then_return(reservoir_def) + decoy.when(mock_labware_view.get_definition("reservoir-id")).then_return( + reservoir_def + ) - decoy.when(labware_view.get_labware_offset_vector("plate-id")).then_return( + decoy.when(mock_labware_view.get_labware_offset_vector("plate-id")).then_return( plate_offset ) - decoy.when(labware_view.get_labware_offset_vector("off-deck-plate-id")).then_return( - off_deck_lw_offset - ) - decoy.when(labware_view.get_labware_offset_vector("reservoir-id")).then_return( + decoy.when( + mock_labware_view.get_labware_offset_vector("off-deck-plate-id") + ).then_return(off_deck_lw_offset) + decoy.when(mock_labware_view.get_labware_offset_vector("reservoir-id")).then_return( reservoir_offset ) decoy.when( - addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) + mock_addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) ).then_return(Point(1, 2, 3)) decoy.when( - addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_4.id) + mock_addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_4.id) ).then_return(Point(4, 5, 6)) plate_z = subject.get_labware_highest_z("plate-id") @@ -542,9 +702,9 @@ def test_get_all_obstacle_highest_z_with_staging_area( decoy: Decoy, well_plate_def: LabwareDefinition, falcon_tuberack_def: LabwareDefinition, - labware_view: LabwareView, - module_view: ModuleView, - addressable_area_view: AddressableAreaView, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, + mock_addressable_area_view: AddressableAreaView, subject: GeometryView, ) -> None: """It should get the highest Z amongst all labware including staging area.""" @@ -566,31 +726,31 @@ def test_get_all_obstacle_highest_z_with_staging_area( plate_offset = LabwareOffsetVector(x=1, y=-2, z=3) staging_lw_offset = LabwareOffsetVector(x=1, y=-2, z=3) - decoy.when(module_view.get_all()).then_return([]) - decoy.when(addressable_area_view.get_all()).then_return([]) + decoy.when(mock_module_view.get_all()).then_return([]) + decoy.when(mock_addressable_area_view.get_all()).then_return([]) - decoy.when(labware_view.get_all()).then_return([plate, staging_lw]) - decoy.when(labware_view.get("plate-id")).then_return(plate) - decoy.when(labware_view.get("staging-id")).then_return(staging_lw) + decoy.when(mock_labware_view.get_all()).then_return([plate, staging_lw]) + decoy.when(mock_labware_view.get("plate-id")).then_return(plate) + decoy.when(mock_labware_view.get("staging-id")).then_return(staging_lw) - decoy.when(labware_view.get_definition("plate-id")).then_return(well_plate_def) - decoy.when(labware_view.get_definition("staging-id")).then_return( + decoy.when(mock_labware_view.get_definition("plate-id")).then_return(well_plate_def) + decoy.when(mock_labware_view.get_definition("staging-id")).then_return( falcon_tuberack_def # Something tall. ) - decoy.when(labware_view.get_labware_offset_vector("plate-id")).then_return( + decoy.when(mock_labware_view.get_labware_offset_vector("plate-id")).then_return( plate_offset ) - decoy.when(labware_view.get_labware_offset_vector("staging-id")).then_return( + decoy.when(mock_labware_view.get_labware_offset_vector("staging-id")).then_return( staging_lw_offset ) decoy.when( - addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) + mock_addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) ).then_return(Point(1, 2, 3)) - decoy.when(addressable_area_view.get_addressable_area_position("D4")).then_return( - Point(4, 5, 6) - ) + decoy.when( + mock_addressable_area_view.get_addressable_area_position("D4") + ).then_return(Point(4, 5, 6)) staging_z = subject.get_labware_highest_z("staging-id") all_z = subject.get_all_obstacle_highest_z() @@ -600,21 +760,21 @@ def test_get_all_obstacle_highest_z_with_staging_area( def test_get_all_obstacle_highest_z_with_modules( decoy: Decoy, - labware_view: LabwareView, - module_view: ModuleView, - addressable_area_view: AddressableAreaView, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, + mock_addressable_area_view: AddressableAreaView, subject: GeometryView, ) -> None: """It should get the highest Z including modules.""" module_1 = LoadedModule.construct(id="module-id-1") # type: ignore[call-arg] module_2 = LoadedModule.construct(id="module-id-2") # type: ignore[call-arg] - decoy.when(labware_view.get_all()).then_return([]) - decoy.when(addressable_area_view.get_all()).then_return([]) + decoy.when(mock_labware_view.get_all()).then_return([]) + decoy.when(mock_addressable_area_view.get_all()).then_return([]) - decoy.when(module_view.get_all()).then_return([module_1, module_2]) - decoy.when(module_view.get_overall_height("module-id-1")).then_return(42.0) - decoy.when(module_view.get_overall_height("module-id-2")).then_return(1337.0) + decoy.when(mock_module_view.get_all()).then_return([module_1, module_2]) + decoy.when(mock_module_view.get_overall_height("module-id-1")).then_return(42.0) + decoy.when(mock_module_view.get_overall_height("module-id-2")).then_return(1337.0) result = subject.get_all_obstacle_highest_z() @@ -623,20 +783,20 @@ def test_get_all_obstacle_highest_z_with_modules( def test_get_all_obstacle_highest_z_with_fixtures( decoy: Decoy, - labware_view: LabwareView, - module_view: ModuleView, - addressable_area_view: AddressableAreaView, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, + mock_addressable_area_view: AddressableAreaView, subject: GeometryView, ) -> None: """It should get the highest Z including fixtures.""" - decoy.when(labware_view.get_all()).then_return([]) - decoy.when(module_view.get_all()).then_return([]) + decoy.when(mock_labware_view.get_all()).then_return([]) + decoy.when(mock_module_view.get_all()).then_return([]) - decoy.when(addressable_area_view.get_all_cutout_fixtures()).then_return( + decoy.when(mock_addressable_area_view.get_all_cutout_fixtures()).then_return( ["abc", "xyz"] ) - decoy.when(addressable_area_view.get_fixture_height("abc")).then_return(42.0) - decoy.when(addressable_area_view.get_fixture_height("xyz")).then_return(1337.0) + decoy.when(mock_addressable_area_view.get_fixture_height("abc")).then_return(42.0) + decoy.when(mock_addressable_area_view.get_fixture_height("xyz")).then_return(1337.0) result = subject.get_all_obstacle_highest_z() @@ -645,8 +805,8 @@ def test_get_all_obstacle_highest_z_with_fixtures( def test_get_highest_z_in_slot_with_single_labware( decoy: Decoy, - labware_view: LabwareView, - addressable_area_view: AddressableAreaView, + mock_labware_view: LabwareView, + mock_addressable_area_view: AddressableAreaView, subject: GeometryView, well_plate_def: LabwareDefinition, ) -> None: @@ -662,21 +822,21 @@ def test_get_highest_z_in_slot_with_single_labware( slot_pos = Point(1, 2, 3) calibration_offset = LabwareOffsetVector(x=1, y=-2, z=3) - decoy.when(labware_view.get_by_slot(DeckSlotName.SLOT_3)).then_return( + decoy.when(mock_labware_view.get_by_slot(DeckSlotName.SLOT_3)).then_return( labware_in_slot ) - decoy.when(labware_view.get_id_by_labware("just-labware-id")).then_raise( + decoy.when(mock_labware_view.get_id_by_labware("just-labware-id")).then_raise( errors.LabwareNotLoadedOnLabwareError("no more labware") ) - decoy.when(labware_view.get("just-labware-id")).then_return(labware_in_slot) - decoy.when(labware_view.get_definition("just-labware-id")).then_return( + decoy.when(mock_labware_view.get("just-labware-id")).then_return(labware_in_slot) + decoy.when(mock_labware_view.get_definition("just-labware-id")).then_return( well_plate_def ) - decoy.when(labware_view.get_labware_offset_vector("just-labware-id")).then_return( - calibration_offset - ) decoy.when( - addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) + mock_labware_view.get_labware_offset_vector("just-labware-id") + ).then_return(calibration_offset) + decoy.when( + mock_addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) ).then_return(slot_pos) expected_highest_z = well_plate_def.dimensions.zDimension + 3 + 3 @@ -688,11 +848,11 @@ def test_get_highest_z_in_slot_with_single_labware( def test_get_highest_z_in_slot_with_single_module( decoy: Decoy, - labware_view: LabwareView, - module_view: ModuleView, - addressable_area_view: AddressableAreaView, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, + mock_addressable_area_view: AddressableAreaView, subject: GeometryView, - ot2_standard_deck_def: DeckDefinitionV4, + ot2_standard_deck_def: DeckDefinitionV5, ) -> None: """It should get the highest Z in slot with just a single module.""" # Case: Slot has a module that doesn't have any labware on it. Highest z is equal to module height. @@ -702,14 +862,21 @@ def test_get_highest_z_in_slot_with_single_module( location=DeckSlotLocation(slotName=DeckSlotName.SLOT_4), ) - decoy.when(module_view.get_by_slot(DeckSlotName.SLOT_3)).then_return(module_in_slot) - decoy.when(labware_view.get_id_by_module("only-module")).then_raise( + decoy.when(mock_module_view.get_by_slot(DeckSlotName.SLOT_3)).then_return( + module_in_slot + ) + decoy.when(mock_labware_view.get_id_by_module("only-module")).then_raise( errors.LabwareNotLoadedOnModuleError("only module") ) - decoy.when(labware_view.get_deck_definition()).then_return(ot2_standard_deck_def) - decoy.when(module_view.get_module_highest_z(module_id="only-module")).then_return( - 12345 + decoy.when(mock_labware_view.get_deck_definition()).then_return( + ot2_standard_deck_def ) + decoy.when( + mock_module_view.get_module_highest_z( + module_id="only-module", + addressable_areas=mock_addressable_area_view, + ) + ).then_return(12345) assert ( subject.get_highest_z_in_slot(DeckSlotLocation(slotName=DeckSlotName.SLOT_3)) @@ -722,8 +889,8 @@ def test_get_highest_z_in_slot_with_single_module( # in an easier-to-understand manner. def test_get_highest_z_in_slot_with_stacked_labware_on_slot( decoy: Decoy, - labware_view: LabwareView, - addressable_area_view: AddressableAreaView, + mock_labware_view: LabwareView, + mock_addressable_area_view: AddressableAreaView, subject: GeometryView, well_plate_def: LabwareDefinition, ) -> None: @@ -755,50 +922,50 @@ def test_get_highest_z_in_slot_with_stacked_labware_on_slot( slot_pos = Point(11, 22, 33) top_lw_lpc_offset = LabwareOffsetVector(x=1, y=-2, z=3) - decoy.when(labware_view.get_by_slot(DeckSlotName.SLOT_3)).then_return( + decoy.when(mock_labware_view.get_by_slot(DeckSlotName.SLOT_3)).then_return( labware_in_slot ) - decoy.when(labware_view.get_id_by_labware("bottom-labware-id")).then_return( + decoy.when(mock_labware_view.get_id_by_labware("bottom-labware-id")).then_return( "middle-labware-id" ) - decoy.when(labware_view.get_id_by_labware("middle-labware-id")).then_return( + decoy.when(mock_labware_view.get_id_by_labware("middle-labware-id")).then_return( "top-labware-id" ) - decoy.when(labware_view.get_id_by_labware("top-labware-id")).then_raise( + decoy.when(mock_labware_view.get_id_by_labware("top-labware-id")).then_raise( errors.LabwareNotLoadedOnLabwareError("top labware") ) - decoy.when(labware_view.get("bottom-labware-id")).then_return(labware_in_slot) - decoy.when(labware_view.get("middle-labware-id")).then_return(middle_labware) - decoy.when(labware_view.get("top-labware-id")).then_return(top_labware) + decoy.when(mock_labware_view.get("bottom-labware-id")).then_return(labware_in_slot) + decoy.when(mock_labware_view.get("middle-labware-id")).then_return(middle_labware) + decoy.when(mock_labware_view.get("top-labware-id")).then_return(top_labware) - decoy.when(labware_view.get_definition("top-labware-id")).then_return( + decoy.when(mock_labware_view.get_definition("top-labware-id")).then_return( well_plate_def ) - decoy.when(labware_view.get_labware_offset_vector("top-labware-id")).then_return( - top_lw_lpc_offset - ) - decoy.when(labware_view.get_dimensions("middle-labware-id")).then_return( + decoy.when( + mock_labware_view.get_labware_offset_vector("top-labware-id") + ).then_return(top_lw_lpc_offset) + decoy.when(mock_labware_view.get_dimensions("middle-labware-id")).then_return( Dimensions(x=10, y=20, z=30) ) - decoy.when(labware_view.get_dimensions("bottom-labware-id")).then_return( + decoy.when(mock_labware_view.get_dimensions("bottom-labware-id")).then_return( Dimensions(x=11, y=12, z=13) ) decoy.when( - labware_view.get_labware_overlap_offsets( + mock_labware_view.get_labware_overlap_offsets( "top-labware-id", below_labware_name="middle-labware-name" ) ).then_return(OverlapOffset(x=4, y=5, z=6)) decoy.when( - labware_view.get_labware_overlap_offsets( + mock_labware_view.get_labware_overlap_offsets( "middle-labware-id", below_labware_name="bottom-labware-name" ) ).then_return(OverlapOffset(x=7, y=8, z=9)) decoy.when( - addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) + mock_addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) ).then_return(slot_pos) expected_highest_z = ( @@ -815,12 +982,12 @@ def test_get_highest_z_in_slot_with_stacked_labware_on_slot( # in an easier-to-understand manner. def test_get_highest_z_in_slot_with_labware_stack_on_module( decoy: Decoy, - labware_view: LabwareView, - module_view: ModuleView, - addressable_area_view: AddressableAreaView, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, + mock_addressable_area_view: AddressableAreaView, subject: GeometryView, well_plate_def: LabwareDefinition, - ot2_standard_deck_def: DeckDefinitionV4, + ot2_standard_deck_def: DeckDefinitionV5, ) -> None: """It should get the highest z in slot of labware on module. @@ -849,54 +1016,63 @@ def test_get_highest_z_in_slot_with_labware_stack_on_module( slot_pos = Point(11, 22, 33) top_lw_lpc_offset = LabwareOffsetVector(x=1, y=-2, z=3) - decoy.when(module_view.get("module-id")).then_return(module_on_slot) - decoy.when(module_view.get_by_slot(DeckSlotName.SLOT_3)).then_return(module_on_slot) + decoy.when(mock_module_view.get("module-id")).then_return(module_on_slot) + decoy.when(mock_module_view.get_by_slot(DeckSlotName.SLOT_3)).then_return( + module_on_slot + ) - decoy.when(labware_view.get_id_by_module("module-id")).then_return("adapter-id") - decoy.when(labware_view.get_id_by_labware("adapter-id")).then_return( + decoy.when(mock_labware_view.get_id_by_module("module-id")).then_return( + "adapter-id" + ) + decoy.when(mock_labware_view.get_id_by_labware("adapter-id")).then_return( "top-labware-id" ) - decoy.when(labware_view.get_id_by_labware("top-labware-id")).then_raise( + decoy.when(mock_labware_view.get_id_by_labware("top-labware-id")).then_raise( errors.LabwareNotLoadedOnLabwareError("top labware") ) - decoy.when(labware_view.get_deck_definition()).then_return(ot2_standard_deck_def) - decoy.when(labware_view.get_definition("top-labware-id")).then_return( + decoy.when(mock_labware_view.get_deck_definition()).then_return( + ot2_standard_deck_def + ) + decoy.when(mock_labware_view.get_definition("top-labware-id")).then_return( well_plate_def ) - decoy.when(labware_view.get("adapter-id")).then_return(adapter) - decoy.when(labware_view.get("top-labware-id")).then_return(top_labware) - decoy.when(labware_view.get_labware_offset_vector("top-labware-id")).then_return( - top_lw_lpc_offset - ) - decoy.when(labware_view.get_dimensions("adapter-id")).then_return( + decoy.when(mock_labware_view.get("adapter-id")).then_return(adapter) + decoy.when(mock_labware_view.get("top-labware-id")).then_return(top_labware) + decoy.when( + mock_labware_view.get_labware_offset_vector("top-labware-id") + ).then_return(top_lw_lpc_offset) + decoy.when(mock_labware_view.get_dimensions("adapter-id")).then_return( Dimensions(x=10, y=20, z=30) ) decoy.when( - labware_view.get_labware_overlap_offsets( + mock_labware_view.get_labware_overlap_offsets( labware_id="top-labware-id", below_labware_name="adapter-name" ) ).then_return(OverlapOffset(x=4, y=5, z=6)) - decoy.when(module_view.get_location("module-id")).then_return( + decoy.when(mock_module_view.get_location("module-id")).then_return( DeckSlotLocation(slotName=DeckSlotName.SLOT_3) ) decoy.when( - module_view.get_nominal_module_offset(module_id="module-id") + mock_module_view.get_nominal_module_offset( + module_id="module-id", + addressable_areas=mock_addressable_area_view, + ) ).then_return(LabwareOffsetVector(x=40, y=50, z=60)) - decoy.when(module_view.get_connected_model("module-id")).then_return( + decoy.when(mock_module_view.get_connected_model("module-id")).then_return( ModuleModel.TEMPERATURE_MODULE_V2 ) decoy.when( - labware_view.get_module_overlap_offsets( + mock_labware_view.get_module_overlap_offsets( "adapter-id", ModuleModel.TEMPERATURE_MODULE_V2 ) ).then_return(OverlapOffset(x=1.1, y=2.2, z=3.3)) decoy.when( - addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) + mock_addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) ).then_return(slot_pos) expected_highest_z = ( @@ -923,9 +1099,9 @@ def test_get_highest_z_in_slot_with_labware_stack_on_module( def test_get_min_travel_z( decoy: Decoy, well_plate_def: LabwareDefinition, - labware_view: LabwareView, - module_view: ModuleView, - addressable_area_view: AddressableAreaView, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, + mock_addressable_area_view: AddressableAreaView, location: Optional[CurrentWell], min_z_height: Optional[float], expected_min_z: float, @@ -940,18 +1116,20 @@ def test_get_min_travel_z( offsetId="offset-id", ) - decoy.when(labware_view.get("labware-id")).then_return(labware_data) - decoy.when(labware_view.get_definition("labware-id")).then_return(well_plate_def) - decoy.when(labware_view.get_labware_offset_vector("labware-id")).then_return( + decoy.when(mock_labware_view.get("labware-id")).then_return(labware_data) + decoy.when(mock_labware_view.get_definition("labware-id")).then_return( + well_plate_def + ) + decoy.when(mock_labware_view.get_labware_offset_vector("labware-id")).then_return( LabwareOffsetVector(x=0, y=0, z=3) ) decoy.when( - addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) + mock_addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_3.id) ).then_return(Point(0, 0, 3)) - decoy.when(module_view.get_all()).then_return([]) - decoy.when(labware_view.get_all()).then_return([]) - decoy.when(addressable_area_view.get_all()).then_return([]) + decoy.when(mock_module_view.get_all()).then_return([]) + decoy.when(mock_labware_view.get_all()).then_return([]) + decoy.when(mock_addressable_area_view.get_all()).then_return([]) min_travel_z = subject.get_min_travel_z( "pipette-id", "labware-id", location, min_z_height @@ -963,8 +1141,8 @@ def test_get_min_travel_z( def test_get_labware_position( decoy: Decoy, well_plate_def: LabwareDefinition, - labware_view: LabwareView, - addressable_area_view: AddressableAreaView, + mock_labware_view: LabwareView, + mock_addressable_area_view: AddressableAreaView, subject: GeometryView, ) -> None: """It should return the slot position plus calibrated offset.""" @@ -978,13 +1156,15 @@ def test_get_labware_position( calibration_offset = LabwareOffsetVector(x=1, y=-2, z=3) slot_pos = Point(4, 5, 6) - decoy.when(labware_view.get("labware-id")).then_return(labware_data) - decoy.when(labware_view.get_definition("labware-id")).then_return(well_plate_def) - decoy.when(labware_view.get_labware_offset_vector("labware-id")).then_return( + decoy.when(mock_labware_view.get("labware-id")).then_return(labware_data) + decoy.when(mock_labware_view.get_definition("labware-id")).then_return( + well_plate_def + ) + decoy.when(mock_labware_view.get_labware_offset_vector("labware-id")).then_return( calibration_offset ) decoy.when( - addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_4.id) + mock_addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_4.id) ).then_return(slot_pos) position = subject.get_labware_position(labware_id="labware-id") @@ -999,8 +1179,8 @@ def test_get_labware_position( def test_get_well_position( decoy: Decoy, well_plate_def: LabwareDefinition, - labware_view: LabwareView, - addressable_area_view: AddressableAreaView, + mock_labware_view: LabwareView, + mock_addressable_area_view: AddressableAreaView, subject: GeometryView, ) -> None: """It should be able to get the position of a well top in a labware.""" @@ -1015,15 +1195,17 @@ def test_get_well_position( slot_pos = Point(4, 5, 6) well_def = well_plate_def.wells["B2"] - decoy.when(labware_view.get("labware-id")).then_return(labware_data) - decoy.when(labware_view.get_definition("labware-id")).then_return(well_plate_def) - decoy.when(labware_view.get_labware_offset_vector("labware-id")).then_return( + decoy.when(mock_labware_view.get("labware-id")).then_return(labware_data) + decoy.when(mock_labware_view.get_definition("labware-id")).then_return( + well_plate_def + ) + decoy.when(mock_labware_view.get_labware_offset_vector("labware-id")).then_return( calibration_offset ) decoy.when( - addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_4.id) + mock_addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_4.id) ).then_return(slot_pos) - decoy.when(labware_view.get_well_definition("labware-id", "B2")).then_return( + decoy.when(mock_labware_view.get_well_definition("labware-id", "B2")).then_return( well_def ) @@ -1039,12 +1221,12 @@ def test_get_well_position( def test_get_well_height( decoy: Decoy, well_plate_def: LabwareDefinition, - labware_view: LabwareView, + mock_labware_view: LabwareView, subject: GeometryView, ) -> None: """It should be able to get the well height.""" well_def = well_plate_def.wells["B2"] - decoy.when(labware_view.get_well_definition("labware-id", "B2")).then_return( + decoy.when(mock_labware_view.get_well_definition("labware-id", "B2")).then_return( well_def ) assert subject.get_well_height("labware-id", "B2") == 10.67 @@ -1053,10 +1235,10 @@ def test_get_well_height( def test_get_module_labware_well_position( decoy: Decoy, well_plate_def: LabwareDefinition, - labware_view: LabwareView, - module_view: ModuleView, - addressable_area_view: AddressableAreaView, - ot2_standard_deck_def: DeckDefinitionV4, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, + mock_addressable_area_view: AddressableAreaView, + ot2_standard_deck_def: DeckDefinitionV5, subject: GeometryView, ) -> None: """It should be able to get the position of a well top in a labware on module.""" @@ -1071,35 +1253,42 @@ def test_get_module_labware_well_position( slot_pos = Point(4, 5, 6) well_def = well_plate_def.wells["B2"] - decoy.when(labware_view.get("labware-id")).then_return(labware_data) - decoy.when(labware_view.get_definition("labware-id")).then_return(well_plate_def) - decoy.when(labware_view.get_labware_offset_vector("labware-id")).then_return( + decoy.when(mock_labware_view.get("labware-id")).then_return(labware_data) + decoy.when(mock_labware_view.get_definition("labware-id")).then_return( + well_plate_def + ) + decoy.when(mock_labware_view.get_labware_offset_vector("labware-id")).then_return( calibration_offset ) decoy.when( - addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_4.id) + mock_addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_4.id) ).then_return(slot_pos) - decoy.when(labware_view.get_well_definition("labware-id", "B2")).then_return( + decoy.when(mock_labware_view.get_well_definition("labware-id", "B2")).then_return( well_def ) - decoy.when(module_view.get_location("module-id")).then_return( + decoy.when(mock_module_view.get_location("module-id")).then_return( DeckSlotLocation(slotName=DeckSlotName.SLOT_4) ) - decoy.when(labware_view.get_deck_definition()).then_return(ot2_standard_deck_def) + decoy.when(mock_labware_view.get_deck_definition()).then_return( + ot2_standard_deck_def + ) decoy.when( - module_view.get_nominal_module_offset(module_id="module-id") + mock_module_view.get_nominal_module_offset( + module_id="module-id", + addressable_areas=mock_addressable_area_view, + ) ).then_return(LabwareOffsetVector(x=4, y=5, z=6)) - decoy.when(module_view.get_module_calibration_offset("module-id")).then_return( + decoy.when(mock_module_view.get_module_calibration_offset("module-id")).then_return( ModuleOffsetData( moduleOffsetVector=ModuleOffsetVector(x=0, y=0, z=0), location=DeckSlotLocation(slotName=DeckSlotName.SLOT_3), ) ) - decoy.when(module_view.get_connected_model("module-id")).then_return( + decoy.when(mock_module_view.get_connected_model("module-id")).then_return( ModuleModel.MAGNETIC_MODULE_V2 ) decoy.when( - labware_view.get_module_overlap_offsets( + mock_labware_view.get_module_overlap_offsets( "labware-id", ModuleModel.MAGNETIC_MODULE_V2 ) ).then_return(OverlapOffset(x=0, y=0, z=0)) @@ -1115,8 +1304,8 @@ def test_get_module_labware_well_position( def test_get_well_position_with_top_offset( decoy: Decoy, well_plate_def: LabwareDefinition, - labware_view: LabwareView, - addressable_area_view: AddressableAreaView, + mock_labware_view: LabwareView, + mock_addressable_area_view: AddressableAreaView, subject: GeometryView, ) -> None: """It should be able to get the position of a well top in a labware.""" @@ -1131,15 +1320,17 @@ def test_get_well_position_with_top_offset( slot_pos = Point(4, 5, 6) well_def = well_plate_def.wells["B2"] - decoy.when(labware_view.get("labware-id")).then_return(labware_data) - decoy.when(labware_view.get_definition("labware-id")).then_return(well_plate_def) - decoy.when(labware_view.get_labware_offset_vector("labware-id")).then_return( + decoy.when(mock_labware_view.get("labware-id")).then_return(labware_data) + decoy.when(mock_labware_view.get_definition("labware-id")).then_return( + well_plate_def + ) + decoy.when(mock_labware_view.get_labware_offset_vector("labware-id")).then_return( calibration_offset ) decoy.when( - addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_4.id) + mock_addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_4.id) ).then_return(slot_pos) - decoy.when(labware_view.get_well_definition("labware-id", "B2")).then_return( + decoy.when(mock_labware_view.get_well_definition("labware-id", "B2")).then_return( well_def ) @@ -1162,8 +1353,8 @@ def test_get_well_position_with_top_offset( def test_get_well_position_with_bottom_offset( decoy: Decoy, well_plate_def: LabwareDefinition, - labware_view: LabwareView, - addressable_area_view: AddressableAreaView, + mock_labware_view: LabwareView, + mock_addressable_area_view: AddressableAreaView, subject: GeometryView, ) -> None: """It should be able to get the position of a well bottom in a labware.""" @@ -1178,15 +1369,17 @@ def test_get_well_position_with_bottom_offset( slot_pos = Point(4, 5, 6) well_def = well_plate_def.wells["B2"] - decoy.when(labware_view.get("labware-id")).then_return(labware_data) - decoy.when(labware_view.get_definition("labware-id")).then_return(well_plate_def) - decoy.when(labware_view.get_labware_offset_vector("labware-id")).then_return( + decoy.when(mock_labware_view.get("labware-id")).then_return(labware_data) + decoy.when(mock_labware_view.get_definition("labware-id")).then_return( + well_plate_def + ) + decoy.when(mock_labware_view.get_labware_offset_vector("labware-id")).then_return( calibration_offset ) decoy.when( - addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_4.id) + mock_addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_4.id) ).then_return(slot_pos) - decoy.when(labware_view.get_well_definition("labware-id", "B2")).then_return( + decoy.when(mock_labware_view.get_well_definition("labware-id", "B2")).then_return( well_def ) @@ -1209,8 +1402,8 @@ def test_get_well_position_with_bottom_offset( def test_get_well_position_with_center_offset( decoy: Decoy, well_plate_def: LabwareDefinition, - labware_view: LabwareView, - addressable_area_view: AddressableAreaView, + mock_labware_view: LabwareView, + mock_addressable_area_view: AddressableAreaView, subject: GeometryView, ) -> None: """It should be able to get the position of a well center in a labware.""" @@ -1225,15 +1418,17 @@ def test_get_well_position_with_center_offset( slot_pos = Point(4, 5, 6) well_def = well_plate_def.wells["B2"] - decoy.when(labware_view.get("labware-id")).then_return(labware_data) - decoy.when(labware_view.get_definition("labware-id")).then_return(well_plate_def) - decoy.when(labware_view.get_labware_offset_vector("labware-id")).then_return( + decoy.when(mock_labware_view.get("labware-id")).then_return(labware_data) + decoy.when(mock_labware_view.get_definition("labware-id")).then_return( + well_plate_def + ) + decoy.when(mock_labware_view.get_labware_offset_vector("labware-id")).then_return( calibration_offset ) decoy.when( - addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_4.id) + mock_addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_4.id) ).then_return(slot_pos) - decoy.when(labware_view.get_well_definition("labware-id", "B2")).then_return( + decoy.when(mock_labware_view.get_well_definition("labware-id", "B2")).then_return( well_def ) @@ -1256,8 +1451,8 @@ def test_get_well_position_with_center_offset( def test_get_relative_well_location( decoy: Decoy, well_plate_def: LabwareDefinition, - labware_view: LabwareView, - addressable_area_view: AddressableAreaView, + mock_labware_view: LabwareView, + mock_addressable_area_view: AddressableAreaView, subject: GeometryView, ) -> None: """It should get the relative location of a well given an absolute position.""" @@ -1272,15 +1467,17 @@ def test_get_relative_well_location( slot_pos = Point(4, 5, 6) well_def = well_plate_def.wells["B2"] - decoy.when(labware_view.get("labware-id")).then_return(labware_data) - decoy.when(labware_view.get_definition("labware-id")).then_return(well_plate_def) - decoy.when(labware_view.get_labware_offset_vector("labware-id")).then_return( + decoy.when(mock_labware_view.get("labware-id")).then_return(labware_data) + decoy.when(mock_labware_view.get_definition("labware-id")).then_return( + well_plate_def + ) + decoy.when(mock_labware_view.get_labware_offset_vector("labware-id")).then_return( calibration_offset ) decoy.when( - addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_4.id) + mock_addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_4.id) ).then_return(slot_pos) - decoy.when(labware_view.get_well_definition("labware-id", "B2")).then_return( + decoy.when(mock_labware_view.get_well_definition("labware-id", "B2")).then_return( well_def ) @@ -1306,12 +1503,12 @@ def test_get_relative_well_location( def test_get_nominal_effective_tip_length( decoy: Decoy, - labware_view: LabwareView, + mock_labware_view: LabwareView, mock_pipette_view: PipetteView, subject: GeometryView, ) -> None: """It should get the effective tip length from a labware ID and pipette config.""" - decoy.when(labware_view.get_definition_uri("tip-rack-id")).then_return( + decoy.when(mock_labware_view.get_definition_uri("tip-rack-id")).then_return( LabwareUri("opentrons/opentrons_96_tiprack_300ul/1") ) @@ -1323,7 +1520,7 @@ def test_get_nominal_effective_tip_length( ).then_return(10) decoy.when( - labware_view.get_tip_length(labware_id="tip-rack-id", overlap=10) + mock_labware_view.get_tip_length(labware_id="tip-rack-id", overlap=10) ).then_return(100) result = subject.get_nominal_effective_tip_length( @@ -1337,18 +1534,18 @@ def test_get_nominal_effective_tip_length( def test_get_nominal_tip_geometry( decoy: Decoy, tip_rack_def: LabwareDefinition, - labware_view: LabwareView, + mock_labware_view: LabwareView, mock_pipette_view: PipetteView, subject: GeometryView, ) -> None: """It should get a "well's" tip geometry.""" well_def = tip_rack_def.wells["B2"] - decoy.when(labware_view.get_definition_uri("tip-rack-id")).then_return( + decoy.when(mock_labware_view.get_definition_uri("tip-rack-id")).then_return( LabwareUri("opentrons/opentrons_96_tiprack_300ul/1") ) - decoy.when(labware_view.get_well_definition("tip-rack-id", "B2")).then_return( + decoy.when(mock_labware_view.get_well_definition("tip-rack-id", "B2")).then_return( well_def ) @@ -1360,7 +1557,7 @@ def test_get_nominal_tip_geometry( ).then_return(10) decoy.when( - labware_view.get_tip_length(labware_id="tip-rack-id", overlap=10) + mock_labware_view.get_tip_length(labware_id="tip-rack-id", overlap=10) ).then_return(100) result = subject.get_nominal_tip_geometry( @@ -1377,14 +1574,14 @@ def test_get_nominal_tip_geometry( def test_get_nominal_tip_geometry_raises( decoy: Decoy, tip_rack_def: LabwareDefinition, - labware_view: LabwareView, + mock_labware_view: LabwareView, subject: GeometryView, ) -> None: """It should raise LabwareIsNotTipRackError if well is not circular.""" well_def = tip_rack_def.wells["B2"] well_def.shape = "rectangular" - decoy.when(labware_view.get_well_definition("tip-rack-id", "B2")).then_return( + decoy.when(mock_labware_view.get_well_definition("tip-rack-id", "B2")).then_return( well_def ) @@ -1396,18 +1593,20 @@ def test_get_nominal_tip_geometry_raises( def test_get_tip_drop_location( decoy: Decoy, - labware_view: LabwareView, + mock_labware_view: LabwareView, mock_pipette_view: PipetteView, subject: GeometryView, tip_rack_def: LabwareDefinition, ) -> None: """It should get relative drop tip location for a pipette/labware combo.""" - decoy.when(labware_view.get_definition("tip-rack-id")).then_return(tip_rack_def) + decoy.when(mock_labware_view.get_definition("tip-rack-id")).then_return( + tip_rack_def + ) decoy.when(mock_pipette_view.get_return_tip_scale("pipette-id")).then_return(0.5) decoy.when( - labware_view.get_tip_drop_z_offset( + mock_labware_view.get_tip_drop_z_offset( labware_id="tip-rack-id", length_scale=0.5, additional_offset=3 ) ).then_return(1337) @@ -1426,12 +1625,14 @@ def test_get_tip_drop_location( def test_get_tip_drop_location_with_non_tiprack( decoy: Decoy, - labware_view: LabwareView, + mock_labware_view: LabwareView, subject: GeometryView, reservoir_def: LabwareDefinition, ) -> None: """It should get relative drop tip location for a labware that is not a tiprack.""" - decoy.when(labware_view.get_definition("labware-id")).then_return(reservoir_def) + decoy.when(mock_labware_view.get_definition("labware-id")).then_return( + reservoir_def + ) location = subject.get_checked_tip_drop_location( pipette_id="pipette-id", @@ -1450,12 +1651,14 @@ def test_get_tip_drop_location_with_non_tiprack( def test_get_tip_drop_explicit_location( decoy: Decoy, - labware_view: LabwareView, + mock_labware_view: LabwareView, subject: GeometryView, tip_rack_def: LabwareDefinition, ) -> None: """It should pass the location through if origin is not WellOrigin.DROP_TIP.""" - decoy.when(labware_view.get_definition("tip-rack-id")).then_return(tip_rack_def) + decoy.when(mock_labware_view.get_definition("tip-rack-id")).then_return( + tip_rack_def + ) input_location = DropTipWellLocation( origin=DropTipWellOrigin.TOP, @@ -1474,12 +1677,12 @@ def test_get_tip_drop_explicit_location( def test_get_ancestor_slot_name( decoy: Decoy, - labware_view: LabwareView, - module_view: ModuleView, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, subject: GeometryView, ) -> None: """It should get name of ancestor slot of labware.""" - decoy.when(labware_view.get("labware-1")).then_return( + decoy.when(mock_labware_view.get("labware-1")).then_return( LoadedLabware( id="labware-1", loadName="load-name", @@ -1489,7 +1692,7 @@ def test_get_ancestor_slot_name( ) assert subject.get_ancestor_slot_name("labware-1") == DeckSlotName.SLOT_4 - decoy.when(labware_view.get("labware-2")).then_return( + decoy.when(mock_labware_view.get("labware-2")).then_return( LoadedLabware( id="labware-2", loadName="load-name", @@ -1497,7 +1700,7 @@ def test_get_ancestor_slot_name( location=ModuleLocation(moduleId="4321"), ) ) - decoy.when(module_view.get_location("4321")).then_return( + decoy.when(mock_module_view.get_location("4321")).then_return( DeckSlotLocation(slotName=DeckSlotName.SLOT_1) ) assert subject.get_ancestor_slot_name("labware-2") == DeckSlotName.SLOT_1 @@ -1505,8 +1708,8 @@ def test_get_ancestor_slot_name( def test_ensure_location_not_occupied_raises( decoy: Decoy, - labware_view: LabwareView, - module_view: ModuleView, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, subject: GeometryView, ) -> None: """It should raise error when labware is present in given location.""" @@ -1515,20 +1718,20 @@ def test_ensure_location_not_occupied_raises( assert subject.ensure_location_not_occupied(location=slot_location) == slot_location # Raise if labware in location - decoy.when(labware_view.raise_if_labware_in_location(slot_location)).then_raise( - errors.LocationIsOccupiedError("Woops!") - ) + decoy.when( + mock_labware_view.raise_if_labware_in_location(slot_location) + ).then_raise(errors.LocationIsOccupiedError("Woops!")) with pytest.raises(errors.LocationIsOccupiedError): subject.ensure_location_not_occupied(location=slot_location) # Raise if module in location module_location = DeckSlotLocation(slotName=DeckSlotName.SLOT_1) - decoy.when(labware_view.raise_if_labware_in_location(module_location)).then_return( - None - ) - decoy.when(module_view.raise_if_module_in_location(module_location)).then_raise( - errors.LocationIsOccupiedError("Woops again!") - ) + decoy.when( + mock_labware_view.raise_if_labware_in_location(module_location) + ).then_return(None) + decoy.when( + mock_module_view.raise_if_module_in_location(module_location) + ).then_raise(errors.LocationIsOccupiedError("Woops again!")) with pytest.raises(errors.LocationIsOccupiedError): subject.ensure_location_not_occupied(location=module_location) @@ -1541,19 +1744,19 @@ def test_ensure_location_not_occupied_raises( def test_get_labware_grip_point( decoy: Decoy, - labware_view: LabwareView, - module_view: ModuleView, - addressable_area_view: AddressableAreaView, - ot2_standard_deck_def: DeckDefinitionV4, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, + mock_addressable_area_view: AddressableAreaView, + ot2_standard_deck_def: DeckDefinitionV5, subject: GeometryView, ) -> None: """It should get the grip point of the labware at the specified location.""" decoy.when( - labware_view.get_grip_height_from_labware_bottom("labware-id") + mock_labware_view.get_grip_height_from_labware_bottom("labware-id") ).then_return(100) decoy.when( - addressable_area_view.get_addressable_area_center(DeckSlotName.SLOT_1.id) + mock_addressable_area_view.get_addressable_area_center(DeckSlotName.SLOT_1.id) ).then_return(Point(x=101, y=102, z=103)) labware_center = subject.get_labware_grip_point( labware_id="labware-id", location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1) @@ -1564,14 +1767,14 @@ def test_get_labware_grip_point( def test_get_labware_grip_point_on_labware( decoy: Decoy, - labware_view: LabwareView, - module_view: ModuleView, - addressable_area_view: AddressableAreaView, - ot2_standard_deck_def: DeckDefinitionV4, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, + mock_addressable_area_view: AddressableAreaView, + ot2_standard_deck_def: DeckDefinitionV5, subject: GeometryView, ) -> None: """It should get the grip point of a labware on another labware.""" - decoy.when(labware_view.get(labware_id="labware-id")).then_return( + decoy.when(mock_labware_view.get(labware_id="labware-id")).then_return( LoadedLabware( id="labware-id", loadName="above-name", @@ -1579,7 +1782,7 @@ def test_get_labware_grip_point_on_labware( location=OnLabwareLocation(labwareId="below-id"), ) ) - decoy.when(labware_view.get(labware_id="below-id")).then_return( + decoy.when(mock_labware_view.get(labware_id="below-id")).then_return( LoadedLabware( id="below-id", loadName="below-name", @@ -1588,18 +1791,18 @@ def test_get_labware_grip_point_on_labware( ) ) - decoy.when(labware_view.get_dimensions("below-id")).then_return( + decoy.when(mock_labware_view.get_dimensions("below-id")).then_return( Dimensions(x=1000, y=1001, z=11) ) decoy.when( - labware_view.get_grip_height_from_labware_bottom("labware-id") + mock_labware_view.get_grip_height_from_labware_bottom("labware-id") ).then_return(100) decoy.when( - labware_view.get_labware_overlap_offsets("labware-id", "below-name") + mock_labware_view.get_labware_overlap_offsets("labware-id", "below-name") ).then_return(OverlapOffset(x=0, y=1, z=6)) decoy.when( - addressable_area_view.get_addressable_area_center(DeckSlotName.SLOT_4.id) + mock_addressable_area_view.get_addressable_area_center(DeckSlotName.SLOT_4.id) ).then_return(Point(x=5, y=9, z=10)) grip_point = subject.get_labware_grip_point( @@ -1611,39 +1814,44 @@ def test_get_labware_grip_point_on_labware( def test_get_labware_grip_point_for_labware_on_module( decoy: Decoy, - labware_view: LabwareView, - module_view: ModuleView, - addressable_area_view: AddressableAreaView, - ot2_standard_deck_def: DeckDefinitionV4, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, + mock_addressable_area_view: AddressableAreaView, + ot2_standard_deck_def: DeckDefinitionV5, subject: GeometryView, ) -> None: """It should return the grip point for labware directly on a module.""" decoy.when( - labware_view.get_grip_height_from_labware_bottom("labware-id") + mock_labware_view.get_grip_height_from_labware_bottom("labware-id") ).then_return(500) - decoy.when(module_view.get_location("module-id")).then_return( + decoy.when(mock_module_view.get_location("module-id")).then_return( DeckSlotLocation(slotName=DeckSlotName.SLOT_4) ) - decoy.when(labware_view.get_deck_definition()).then_return(ot2_standard_deck_def) + decoy.when(mock_labware_view.get_deck_definition()).then_return( + ot2_standard_deck_def + ) decoy.when( - module_view.get_nominal_module_offset(module_id="module-id") + mock_module_view.get_nominal_module_offset( + module_id="module-id", + addressable_areas=mock_addressable_area_view, + ) ).then_return(LabwareOffsetVector(x=1, y=2, z=3)) - decoy.when(module_view.get_connected_model("module-id")).then_return( + decoy.when(mock_module_view.get_connected_model("module-id")).then_return( ModuleModel.MAGNETIC_MODULE_V2 ) decoy.when( - labware_view.get_module_overlap_offsets( + mock_labware_view.get_module_overlap_offsets( "labware-id", ModuleModel.MAGNETIC_MODULE_V2 ) ).then_return(OverlapOffset(x=10, y=20, z=30)) - decoy.when(module_view.get_module_calibration_offset("module-id")).then_return( + decoy.when(mock_module_view.get_module_calibration_offset("module-id")).then_return( ModuleOffsetData( moduleOffsetVector=ModuleOffsetVector(x=100, y=200, z=300), location=DeckSlotLocation(slotName=DeckSlotName.SLOT_4), ) ) decoy.when( - addressable_area_view.get_addressable_area_center(DeckSlotName.SLOT_4.id) + mock_addressable_area_view.get_addressable_area_center(DeckSlotName.SLOT_4.id) ).then_return(Point(100, 200, 300)) result_grip_point = subject.get_labware_grip_point( labware_id="labware-id", location=ModuleLocation(moduleId="module-id") @@ -1665,16 +1873,16 @@ def test_get_labware_grip_point_for_labware_on_module( ) def test_get_extra_waypoints( decoy: Decoy, - labware_view: LabwareView, - module_view: ModuleView, - addressable_area_view: AddressableAreaView, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, + mock_addressable_area_view: AddressableAreaView, location: Optional[CurrentPipetteLocation], should_dodge: bool, expected_waypoints: List[Tuple[float, float]], subject: GeometryView, ) -> None: """It should return extra waypoints if thermocycler should be dodged.""" - decoy.when(labware_view.get("from-labware-id")).then_return( + decoy.when(mock_labware_view.get("from-labware-id")).then_return( LoadedLabware( id="labware1", loadName="load-name1", @@ -1684,17 +1892,17 @@ def test_get_extra_waypoints( ) decoy.when( - addressable_area_view.get_addressable_area_base_slot("area-name") + mock_addressable_area_view.get_addressable_area_base_slot("area-name") ).then_return(DeckSlotName.SLOT_1) decoy.when( - module_view.should_dodge_thermocycler( + mock_module_view.should_dodge_thermocycler( from_slot=DeckSlotName.SLOT_1, to_slot=DeckSlotName.SLOT_2 ) ).then_return(should_dodge) decoy.when( # Assume the subject's Config is for an OT-3, so use an OT-3 slot name. - addressable_area_view.get_addressable_area_center( + mock_addressable_area_view.get_addressable_area_center( addressable_area_name=DeckSlotName.SLOT_C2.id ) ).then_return(Point(x=11, y=22, z=33)) @@ -1706,21 +1914,21 @@ def test_get_extra_waypoints( def test_get_slot_item( decoy: Decoy, - labware_view: LabwareView, - module_view: ModuleView, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, subject: GeometryView, ) -> None: """It should get items in certain slots.""" labware = LoadedLabware.construct(id="cool-labware") # type: ignore[call-arg] module = LoadedModule.construct(id="cool-module") # type: ignore[call-arg] - decoy.when(labware_view.get_by_slot(DeckSlotName.SLOT_1)).then_return(None) - decoy.when(labware_view.get_by_slot(DeckSlotName.SLOT_2)).then_return(labware) - decoy.when(labware_view.get_by_slot(DeckSlotName.SLOT_3)).then_return(None) + decoy.when(mock_labware_view.get_by_slot(DeckSlotName.SLOT_1)).then_return(None) + decoy.when(mock_labware_view.get_by_slot(DeckSlotName.SLOT_2)).then_return(labware) + decoy.when(mock_labware_view.get_by_slot(DeckSlotName.SLOT_3)).then_return(None) - decoy.when(module_view.get_by_slot(DeckSlotName.SLOT_1)).then_return(None) - decoy.when(module_view.get_by_slot(DeckSlotName.SLOT_2)).then_return(None) - decoy.when(module_view.get_by_slot(DeckSlotName.SLOT_3)).then_return(module) + decoy.when(mock_module_view.get_by_slot(DeckSlotName.SLOT_1)).then_return(None) + decoy.when(mock_module_view.get_by_slot(DeckSlotName.SLOT_2)).then_return(None) + decoy.when(mock_module_view.get_by_slot(DeckSlotName.SLOT_3)).then_return(module) assert ( subject.get_slot_item( @@ -1734,16 +1942,16 @@ def test_get_slot_item( def test_get_slot_item_that_is_overflowed_module( decoy: Decoy, - labware_view: LabwareView, - module_view: ModuleView, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, subject: GeometryView, ) -> None: """It should return the module that occupies the slot, even if not loaded on it.""" module = LoadedModule.construct(id="cool-module") # type: ignore[call-arg] - decoy.when(labware_view.get_by_slot(DeckSlotName.SLOT_3)).then_return(None) - decoy.when(module_view.get_by_slot(DeckSlotName.SLOT_3)).then_return(None) + decoy.when(mock_labware_view.get_by_slot(DeckSlotName.SLOT_3)).then_return(None) + decoy.when(mock_module_view.get_by_slot(DeckSlotName.SLOT_3)).then_return(None) decoy.when( - module_view.get_overflowed_module_in_slot(DeckSlotName.SLOT_3) + mock_module_view.get_overflowed_module_in_slot(DeckSlotName.SLOT_3) ).then_return(module) assert subject.get_slot_item(DeckSlotName.SLOT_3) == module @@ -1828,7 +2036,7 @@ class DropTipLocationFinderSpec(NamedTuple): ) def test_get_next_drop_tip_location( decoy: Decoy, - labware_view: LabwareView, + mock_labware_view: LabwareView, mock_pipette_view: PipetteView, subject: GeometryView, labware_slot: DeckSlotName, @@ -1839,9 +2047,9 @@ def test_get_next_drop_tip_location( supported_tip_fixture: pipette_definition.SupportedTipsDefinition, ) -> None: """It should provide the next location to drop tips into within a labware.""" - decoy.when(labware_view.is_fixed_trash(labware_id="abc")).then_return(True) + decoy.when(mock_labware_view.is_fixed_trash(labware_id="abc")).then_return(True) decoy.when( - labware_view.get_well_size(labware_id="abc", well_name="A1") + mock_labware_view.get_well_size(labware_id="abc", well_name="A1") ).then_return((well_size, 0, 0)) if pipette_channels == 96: pip_type = PipetteNameType.P1000_96 @@ -1873,7 +2081,7 @@ def test_get_next_drop_tip_location( ) ) decoy.when(mock_pipette_view.get_mount("pip-123")).then_return(pipette_mount) - decoy.when(labware_view.get("abc")).then_return( + decoy.when(mock_labware_view.get("abc")).then_return( LoadedLabware( id="abc", loadName="load-name2", @@ -1895,12 +2103,12 @@ def test_get_next_drop_tip_location( def test_get_next_drop_tip_location_in_non_trash_labware( decoy: Decoy, - labware_view: LabwareView, + mock_labware_view: LabwareView, mock_pipette_view: PipetteView, subject: GeometryView, ) -> None: """It should provide the default drop tip location when dropping into a non-fixed-trash labware.""" - decoy.when(labware_view.is_fixed_trash(labware_id="abc")).then_return(False) + decoy.when(mock_labware_view.is_fixed_trash(labware_id="abc")).then_return(False) assert subject.get_next_tip_drop_location( labware_id="abc", well_name="A1", pipette_id="pip-123" ) == DropTipWellLocation( @@ -1911,18 +2119,18 @@ def test_get_next_drop_tip_location_in_non_trash_labware( def test_get_final_labware_movement_offset_vectors( decoy: Decoy, - module_view: ModuleView, - labware_view: LabwareView, + mock_module_view: ModuleView, + mock_labware_view: LabwareView, subject: GeometryView, ) -> None: """It should provide the final labware movement offset data based on locations.""" - decoy.when(labware_view.get_deck_default_gripper_offsets()).then_return( + decoy.when(mock_labware_view.get_deck_default_gripper_offsets()).then_return( LabwareMovementOffsetData( pickUpOffset=LabwareOffsetVector(x=1, y=2, z=3), dropOffset=LabwareOffsetVector(x=3, y=2, z=1), ) ) - decoy.when(module_view.get_default_gripper_offsets("module-id")).then_return( + decoy.when(mock_module_view.get_default_gripper_offsets("module-id")).then_return( LabwareMovementOffsetData( pickUpOffset=LabwareOffsetVector(x=11, y=22, z=33), dropOffset=LabwareOffsetVector(x=33, y=22, z=11), @@ -1963,19 +2171,19 @@ def test_ensure_valid_gripper_location(subject: GeometryView) -> None: def test_get_total_nominal_gripper_offset( decoy: Decoy, - labware_view: LabwareView, - module_view: ModuleView, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, subject: GeometryView, ) -> None: """It should calculate the correct gripper offsets given the location and move type..""" - decoy.when(labware_view.get_deck_default_gripper_offsets()).then_return( + decoy.when(mock_labware_view.get_deck_default_gripper_offsets()).then_return( LabwareMovementOffsetData( pickUpOffset=LabwareOffsetVector(x=1, y=2, z=3), dropOffset=LabwareOffsetVector(x=3, y=2, z=1), ) ) - decoy.when(module_view.get_default_gripper_offsets("module-id")).then_return( + decoy.when(mock_module_view.get_default_gripper_offsets("module-id")).then_return( LabwareMovementOffsetData( pickUpOffset=LabwareOffsetVector(x=11, y=22, z=33), dropOffset=LabwareOffsetVector(x=33, y=22, z=11), @@ -1999,23 +2207,23 @@ def test_get_total_nominal_gripper_offset( def test_get_stacked_labware_total_nominal_offset_slot_specific( decoy: Decoy, - labware_view: LabwareView, - module_view: ModuleView, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, subject: GeometryView, ) -> None: """Get nominal offset for stacked labware.""" # Case: labware on adapter on module, adapter has slot-specific offsets - decoy.when(module_view.get_default_gripper_offsets("module-id")).then_return( + decoy.when(mock_module_view.get_default_gripper_offsets("module-id")).then_return( LabwareMovementOffsetData( pickUpOffset=LabwareOffsetVector(x=11, y=22, z=33), dropOffset=LabwareOffsetVector(x=33, y=22, z=11), ) ) - decoy.when(module_view.get_location("module-id")).then_return( + decoy.when(mock_module_view.get_location("module-id")).then_return( DeckSlotLocation(slotName=DeckSlotName.SLOT_C1) ) decoy.when( - labware_view.get_labware_gripper_offsets( + mock_labware_view.get_labware_gripper_offsets( labware_id="adapter-id", slot_name=DeckSlotName.SLOT_C1 ) ).then_return( @@ -2024,7 +2232,7 @@ def test_get_stacked_labware_total_nominal_offset_slot_specific( dropOffset=LabwareOffsetVector(x=300, y=200, z=100), ) ) - decoy.when(labware_view.get_parent_location("adapter-id")).then_return( + decoy.when(mock_labware_view.get_parent_location("adapter-id")).then_return( ModuleLocation(moduleId="module-id") ) result1 = subject.get_total_nominal_gripper_offset_for_move_type( @@ -2042,28 +2250,28 @@ def test_get_stacked_labware_total_nominal_offset_slot_specific( def test_get_stacked_labware_total_nominal_offset_default( decoy: Decoy, - labware_view: LabwareView, - module_view: ModuleView, + mock_labware_view: LabwareView, + mock_module_view: ModuleView, subject: GeometryView, ) -> None: """Get nominal offset for stacked labware.""" # Case: labware on adapter on module, adapter has only default offsets - decoy.when(module_view.get_default_gripper_offsets("module-id")).then_return( + decoy.when(mock_module_view.get_default_gripper_offsets("module-id")).then_return( LabwareMovementOffsetData( pickUpOffset=LabwareOffsetVector(x=11, y=22, z=33), dropOffset=LabwareOffsetVector(x=33, y=22, z=11), ) ) - decoy.when(module_view.get_location("module-id")).then_return( + decoy.when(mock_module_view.get_location("module-id")).then_return( DeckSlotLocation(slotName=DeckSlotName.SLOT_4) ) decoy.when( - labware_view.get_labware_gripper_offsets( + mock_labware_view.get_labware_gripper_offsets( labware_id="adapter-id", slot_name=DeckSlotName.SLOT_C1 ) ).then_return(None) decoy.when( - labware_view.get_labware_gripper_offsets( + mock_labware_view.get_labware_gripper_offsets( labware_id="adapter-id", slot_name=None ) ).then_return( @@ -2072,7 +2280,7 @@ def test_get_stacked_labware_total_nominal_offset_default( dropOffset=LabwareOffsetVector(x=300, y=200, z=100), ) ) - decoy.when(labware_view.get_parent_location("adapter-id")).then_return( + decoy.when(mock_labware_view.get_parent_location("adapter-id")).then_return( ModuleLocation(moduleId="module-id") ) result1 = subject.get_total_nominal_gripper_offset_for_move_type( @@ -2091,8 +2299,8 @@ def test_get_stacked_labware_total_nominal_offset_default( def test_check_gripper_labware_tip_collision( decoy: Decoy, mock_pipette_view: PipetteView, - labware_view: LabwareView, - addressable_area_view: AddressableAreaView, + mock_labware_view: LabwareView, + mock_addressable_area_view: AddressableAreaView, subject: GeometryView, ) -> None: """It should raise a labware movement error if attached tips will collide with the labware during a gripper lift.""" @@ -2138,34 +2346,34 @@ def test_check_gripper_labware_tip_collision( offsetId=None, ) - decoy.when(labware_view.get_definition("labware-id")).then_return(definition) - decoy.when(labware_view.get("labware-id")).then_return(labware_data) + decoy.when(mock_labware_view.get_definition("labware-id")).then_return(definition) + decoy.when(mock_labware_view.get("labware-id")).then_return(labware_data) decoy.when( - addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_1.id) + mock_addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_1.id) ).then_return(Point(1, 2, 3)) calibration_offset = LabwareOffsetVector(x=1, y=-2, z=3) - decoy.when(labware_view.get_labware_offset_vector("labware-id")).then_return( + decoy.when(mock_labware_view.get_labware_offset_vector("labware-id")).then_return( calibration_offset ) decoy.when(subject.get_labware_origin_position("labware-id")).then_return( Point(1, 2, 3) ) - decoy.when(labware_view.get_definition("labware-id")).then_return(definition) + decoy.when(mock_labware_view.get_definition("labware-id")).then_return(definition) decoy.when(subject._get_highest_z_from_labware_data(labware_data)).then_return(1000) - decoy.when(labware_view.get_definition("labware-id")).then_return(definition) + decoy.when(mock_labware_view.get_definition("labware-id")).then_return(definition) decoy.when(subject.get_labware_highest_z("labware-id")).then_return(100.0) decoy.when( - addressable_area_view.get_addressable_area_center( + mock_addressable_area_view.get_addressable_area_center( addressable_area_name=DeckSlotName.SLOT_1.id ) ).then_return(Point(x=11, y=22, z=33)) decoy.when( - labware_view.get_grip_height_from_labware_bottom("labware-id") + mock_labware_view.get_grip_height_from_labware_bottom("labware-id") ).then_return(1.0) - decoy.when(labware_view.get_definition("labware-id")).then_return(definition) + decoy.when(mock_labware_view.get_definition("labware-id")).then_return(definition) decoy.when( subject.get_labware_grip_point( labware_id="labware-id", @@ -2179,3 +2387,216 @@ def test_check_gripper_labware_tip_collision( labware_id="labware-id", current_location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1), ) + + +# Note: Below here, all tests should be done using actual state objects rather than mocks of dependent views. +# I (sf) think this is a better way to do things, but let's try and do it as we add more stuff and see if I'm +# right! + + +@pytest.mark.parametrize("use_mocks", [False]) +def test_get_offset_location_deck_slot( + decoy: Decoy, + labware_store: LabwareStore, + nice_labware_definition: LabwareDefinition, + subject: GeometryView, +) -> None: + """Test if you can get the offset location of a labware in a deck slot.""" + action = SucceedCommandAction( + command=LoadLabware( + id="load-labware-1", + createdAt=datetime.now(), + key="load-labware-1", + status=CommandStatus.SUCCEEDED, + result=LoadLabwareResult( + labwareId="labware-id-1", + definition=nice_labware_definition, + offsetId=None, + ), + params=LoadLabwareParams( + location=DeckSlotLocation(slotName=DeckSlotName.SLOT_C2), + loadName=nice_labware_definition.parameters.loadName, + namespace=nice_labware_definition.namespace, + version=nice_labware_definition.version, + ), + ), + private_result=None, + ) + labware_store.handle_action(action) + offset_location = subject.get_offset_location("labware-id-1") + assert offset_location is not None + assert offset_location.slotName == DeckSlotName.SLOT_C2 + assert offset_location.definitionUri is None + assert offset_location.moduleModel is None + + +@pytest.mark.parametrize("use_mocks", [False]) +def test_get_offset_location_module( + decoy: Decoy, + labware_store: LabwareStore, + module_store: ModuleStore, + nice_labware_definition: LabwareDefinition, + tempdeck_v2_def: ModuleDefinition, + subject: GeometryView, +) -> None: + """Test if you can get the offset of a labware directly on a module.""" + load_module = SucceedCommandAction( + command=LoadModule( + params=LoadModuleParams( + location=DeckSlotLocation(slotName=DeckSlotName.SLOT_A3), + model=ModuleModel.TEMPERATURE_MODULE_V1, + ), + id="load-module-1", + createdAt=datetime.now(), + key="load-module-1", + status=CommandStatus.SUCCEEDED, + result=LoadModuleResult( + moduleId="module-id-1", + definition=tempdeck_v2_def, + model=tempdeck_v2_def.model, + ), + ), + private_result=None, + ) + load_labware = SucceedCommandAction( + command=LoadLabware( + id="load-labware-1", + createdAt=datetime.now(), + key="load-labware-1", + status=CommandStatus.SUCCEEDED, + result=LoadLabwareResult( + labwareId="labware-id-1", + definition=nice_labware_definition, + offsetId=None, + ), + params=LoadLabwareParams( + location=ModuleLocation(moduleId="module-id-1"), + loadName=nice_labware_definition.parameters.loadName, + namespace=nice_labware_definition.namespace, + version=nice_labware_definition.version, + ), + ), + private_result=None, + ) + module_store.handle_action(load_module) + labware_store.handle_action(load_labware) + offset_location = subject.get_offset_location("labware-id-1") + assert offset_location is not None + assert offset_location.slotName == DeckSlotName.SLOT_A3 + assert offset_location.definitionUri is None + assert offset_location.moduleModel == ModuleModel.TEMPERATURE_MODULE_V1 + + +@pytest.mark.parametrize("use_mocks", [False]) +def test_get_offset_location_module_with_adapter( + decoy: Decoy, + labware_store: LabwareStore, + module_store: ModuleStore, + nice_labware_definition: LabwareDefinition, + nice_adapter_definition: LabwareDefinition, + tempdeck_v2_def: ModuleDefinition, + labware_view: LabwareView, + subject: GeometryView, +) -> None: + """Test if you can get the offset of a labware directly on a module.""" + load_module = SucceedCommandAction( + command=LoadModule( + params=LoadModuleParams( + location=DeckSlotLocation(slotName=DeckSlotName.SLOT_A2), + model=ModuleModel.TEMPERATURE_MODULE_V1, + ), + id="load-module-1", + createdAt=datetime.now(), + key="load-module-1", + status=CommandStatus.SUCCEEDED, + result=LoadModuleResult( + moduleId="module-id-1", + definition=tempdeck_v2_def, + model=tempdeck_v2_def.model, + ), + ), + private_result=None, + ) + load_adapter = SucceedCommandAction( + command=LoadLabware( + id="load-adapter-1", + createdAt=datetime.now(), + key="load-adapter-1", + status=CommandStatus.SUCCEEDED, + result=LoadLabwareResult( + labwareId="adapter-id-1", + definition=nice_adapter_definition, + offsetId=None, + ), + params=LoadLabwareParams( + location=ModuleLocation(moduleId="module-id-1"), + loadName=nice_adapter_definition.parameters.loadName, + namespace=nice_adapter_definition.namespace, + version=nice_adapter_definition.version, + ), + ), + private_result=None, + ) + load_labware = SucceedCommandAction( + command=LoadLabware( + id="load-labware-1", + createdAt=datetime.now(), + key="load-labware-1", + status=CommandStatus.SUCCEEDED, + result=LoadLabwareResult( + labwareId="labware-id-1", + definition=nice_labware_definition, + offsetId=None, + ), + params=LoadLabwareParams( + location=OnLabwareLocation(labwareId="adapter-id-1"), + loadName=nice_labware_definition.parameters.loadName, + namespace=nice_labware_definition.namespace, + version=nice_labware_definition.version, + ), + ), + private_result=None, + ) + module_store.handle_action(load_module) + labware_store.handle_action(load_adapter) + labware_store.handle_action(load_labware) + offset_location = subject.get_offset_location("labware-id-1") + assert offset_location is not None + assert offset_location.slotName == DeckSlotName.SLOT_A2 + assert offset_location.definitionUri == labware_view.get_uri_from_definition( + nice_adapter_definition + ) + assert offset_location.moduleModel == ModuleModel.TEMPERATURE_MODULE_V1 + + +@pytest.mark.parametrize("use_mocks", [False]) +def test_get_offset_fails_with_off_deck_labware( + decoy: Decoy, + labware_store: LabwareStore, + nice_labware_definition: LabwareDefinition, + subject: GeometryView, +) -> None: + """You cannot get the offset location for a labware loaded OFF_DECK.""" + action = SucceedCommandAction( + command=LoadLabware( + id="load-labware-1", + createdAt=datetime.now(), + key="load-labware-1", + status=CommandStatus.SUCCEEDED, + result=LoadLabwareResult( + labwareId="labware-id-1", + definition=nice_labware_definition, + offsetId=None, + ), + params=LoadLabwareParams( + location=OFF_DECK_LOCATION, + loadName=nice_labware_definition.parameters.loadName, + namespace=nice_labware_definition.namespace, + version=nice_labware_definition.version, + ), + ), + private_result=None, + ) + labware_store.handle_action(action) + offset_location = subject.get_offset_location("labware-id-1") + assert offset_location is None diff --git a/api/tests/opentrons/protocol_engine/state/test_labware_store.py b/api/tests/opentrons/protocol_engine/state/test_labware_store.py index 2c0c8cdefd9..960ce423194 100644 --- a/api/tests/opentrons/protocol_engine/state/test_labware_store.py +++ b/api/tests/opentrons/protocol_engine/state/test_labware_store.py @@ -4,7 +4,7 @@ from datetime import datetime from opentrons.calibration_storage.helpers import uri_from_details -from opentrons_shared_data.deck.dev_types import DeckDefinitionV4 +from opentrons_shared_data.deck.dev_types import DeckDefinitionV5 from opentrons.protocols.models import LabwareDefinition from opentrons.types import DeckSlotName @@ -28,12 +28,13 @@ from .command_fixtures import ( create_load_labware_command, create_move_labware_command, + create_reload_labware_command, ) @pytest.fixture def subject( - ot2_standard_deck_def: DeckDefinitionV4, + ot2_standard_deck_def: DeckDefinitionV5, ) -> LabwareStore: """Get a LabwareStore test subject.""" return LabwareStore( @@ -43,7 +44,7 @@ def subject( def test_initial_state( - ot2_standard_deck_def: DeckDefinitionV4, + ot2_standard_deck_def: DeckDefinitionV5, subject: LabwareStore, ) -> None: """It should create the labware store with preloaded fixed labware.""" @@ -132,6 +133,64 @@ def test_handles_load_labware( assert subject.state.definitions_by_uri[expected_definition_uri] == well_plate_def +def test_handles_reload_labware( + subject: LabwareStore, + well_plate_def: LabwareDefinition, +) -> None: + """It should override labware data in the state.""" + load_labware = create_load_labware_command( + location=DeckSlotLocation(slotName=DeckSlotName.SLOT_A1), + labware_id="test-labware-id", + definition=well_plate_def, + display_name="display-name", + offset_id=None, + ) + + subject.handle_action( + SucceedCommandAction(private_result=None, command=load_labware) + ) + expected_definition_uri = uri_from_details( + load_name=well_plate_def.parameters.loadName, + namespace=well_plate_def.namespace, + version=well_plate_def.version, + ) + assert ( + subject.state.labware_by_id["test-labware-id"].definitionUri + == expected_definition_uri + ) + + offset_request = LabwareOffsetCreate( + definitionUri="offset-definition-uri", + location=LabwareOffsetLocation(slotName=DeckSlotName.SLOT_1), + vector=LabwareOffsetVector(x=1, y=2, z=3), + ) + subject.handle_action( + AddLabwareOffsetAction( + request=offset_request, + labware_offset_id="offset-id", + created_at=datetime(year=2021, month=1, day=2), + ) + ) + reload_labware = create_reload_labware_command( + labware_id="test-labware-id", + offset_id="offset-id", + ) + subject.handle_action( + SucceedCommandAction(private_result=None, command=reload_labware) + ) + + expected_labware_data = LoadedLabware( + id="test-labware-id", + loadName=well_plate_def.parameters.loadName, + definitionUri=expected_definition_uri, + location=DeckSlotLocation(slotName=DeckSlotName.SLOT_A1), + offsetId="offset-id", + displayName="display-name", + ) + assert subject.state.labware_by_id["test-labware-id"] == expected_labware_data + assert subject.state.definitions_by_uri[expected_definition_uri] == well_plate_def + + def test_handles_add_labware_definition( subject: LabwareStore, well_plate_def: LabwareDefinition, diff --git a/api/tests/opentrons/protocol_engine/state/test_labware_view.py b/api/tests/opentrons/protocol_engine/state/test_labware_view.py index 5e7e96412fa..0f8086de606 100644 --- a/api/tests/opentrons/protocol_engine/state/test_labware_view.py +++ b/api/tests/opentrons/protocol_engine/state/test_labware_view.py @@ -5,7 +5,7 @@ from contextlib import nullcontext as does_not_raise from opentrons_shared_data.deck import load as load_deck -from opentrons_shared_data.deck.dev_types import DeckDefinitionV4 +from opentrons_shared_data.deck.dev_types import DeckDefinitionV5 from opentrons_shared_data.pipette.dev_types import LabwareUri from opentrons_shared_data.labware import load_definition from opentrons_shared_data.labware.labware_definition import ( @@ -110,14 +110,14 @@ def get_labware_view( labware_by_id: Optional[Dict[str, LoadedLabware]] = None, labware_offsets_by_id: Optional[Dict[str, LabwareOffset]] = None, definitions_by_uri: Optional[Dict[str, LabwareDefinition]] = None, - deck_definition: Optional[DeckDefinitionV4] = None, + deck_definition: Optional[DeckDefinitionV5] = None, ) -> LabwareView: """Get a labware view test subject.""" state = LabwareState( labware_by_id=labware_by_id or {}, labware_offsets_by_id=labware_offsets_by_id or {}, definitions_by_uri=definitions_by_uri or {}, - deck_definition=deck_definition or cast(DeckDefinitionV4, {"fake": True}), + deck_definition=deck_definition or cast(DeckDefinitionV5, {"fake": True}), ) return LabwareView(state=state) @@ -696,7 +696,7 @@ def test_get_labware_overlap_offsets() -> None: class ModuleOverlapSpec(NamedTuple): """Spec data to test LabwareView.get_module_overlap_offsets.""" - spec_deck_definition: DeckDefinitionV4 + spec_deck_definition: DeckDefinitionV5 module_model: ModuleModel stacking_offset_with_module: Dict[str, SharedDataOverlapOffset] expected_offset: OverlapOffset @@ -705,7 +705,7 @@ class ModuleOverlapSpec(NamedTuple): module_overlap_specs: List[ModuleOverlapSpec] = [ ModuleOverlapSpec( # Labware on temp module on OT2, with stacking overlap for temp module - spec_deck_definition=load_deck(STANDARD_OT2_DECK, 4), + spec_deck_definition=load_deck(STANDARD_OT2_DECK, 5), module_model=ModuleModel.TEMPERATURE_MODULE_V2, stacking_offset_with_module={ str(ModuleModel.TEMPERATURE_MODULE_V2.value): SharedDataOverlapOffset( @@ -716,7 +716,7 @@ class ModuleOverlapSpec(NamedTuple): ), ModuleOverlapSpec( # Labware on TC Gen1 on OT2, with stacking overlap for TC Gen1 - spec_deck_definition=load_deck(STANDARD_OT2_DECK, 4), + spec_deck_definition=load_deck(STANDARD_OT2_DECK, 5), module_model=ModuleModel.THERMOCYCLER_MODULE_V1, stacking_offset_with_module={ str(ModuleModel.THERMOCYCLER_MODULE_V1.value): SharedDataOverlapOffset( @@ -727,21 +727,21 @@ class ModuleOverlapSpec(NamedTuple): ), ModuleOverlapSpec( # Labware on TC Gen2 on OT2, with no stacking overlap - spec_deck_definition=load_deck(STANDARD_OT2_DECK, 4), + spec_deck_definition=load_deck(STANDARD_OT2_DECK, 5), module_model=ModuleModel.THERMOCYCLER_MODULE_V2, stacking_offset_with_module={}, expected_offset=OverlapOffset(x=0, y=0, z=10.7), ), ModuleOverlapSpec( # Labware on TC Gen2 on Flex, with no stacking overlap - spec_deck_definition=load_deck(STANDARD_OT3_DECK, 4), + spec_deck_definition=load_deck(STANDARD_OT3_DECK, 5), module_model=ModuleModel.THERMOCYCLER_MODULE_V2, stacking_offset_with_module={}, expected_offset=OverlapOffset(x=0, y=0, z=0), ), ModuleOverlapSpec( # Labware on TC Gen2 on Flex, with stacking overlap for TC Gen2 - spec_deck_definition=load_deck(STANDARD_OT3_DECK, 4), + spec_deck_definition=load_deck(STANDARD_OT3_DECK, 5), module_model=ModuleModel.THERMOCYCLER_MODULE_V2, stacking_offset_with_module={ str(ModuleModel.THERMOCYCLER_MODULE_V2.value): SharedDataOverlapOffset( @@ -758,7 +758,7 @@ class ModuleOverlapSpec(NamedTuple): argvalues=module_overlap_specs, ) def test_get_module_overlap_offsets( - spec_deck_definition: DeckDefinitionV4, + spec_deck_definition: DeckDefinitionV5, module_model: ModuleModel, stacking_offset_with_module: Dict[str, SharedDataOverlapOffset], expected_offset: OverlapOffset, @@ -800,7 +800,7 @@ def test_get_default_magnet_height( assert subject.get_default_magnet_height(module_id="module-id", offset=2) == 12.0 -def test_get_deck_definition(ot2_standard_deck_def: DeckDefinitionV4) -> None: +def test_get_deck_definition(ot2_standard_deck_def: DeckDefinitionV5) -> None: """It should get the deck definition from the state.""" subject = get_labware_view(deck_definition=ot2_standard_deck_def) @@ -1404,7 +1404,7 @@ def test_raise_if_labware_cannot_be_stacked_on_labware_on_adapter() -> None: ) -def test_get_deck_gripper_offsets(ot3_standard_deck_def: DeckDefinitionV4) -> None: +def test_get_deck_gripper_offsets(ot3_standard_deck_def: DeckDefinitionV5) -> None: """It should get the deck's gripper offsets.""" subject = get_labware_view(deck_definition=ot3_standard_deck_def) diff --git a/api/tests/opentrons/protocol_engine/state/test_module_store.py b/api/tests/opentrons/protocol_engine/state/test_module_store.py index 1d0d7003496..e6de0a96ac0 100644 --- a/api/tests/opentrons/protocol_engine/state/test_module_store.py +++ b/api/tests/opentrons/protocol_engine/state/test_module_store.py @@ -1,8 +1,9 @@ """Module state store tests.""" -from typing import List +from typing import List, Set, cast, Dict, Optional import pytest from opentrons_shared_data.robot.dev_types import RobotType +from opentrons_shared_data.deck.dev_types import DeckDefinitionV5 from pytest_lazyfixture import lazy_fixture # type: ignore[import-untyped] from opentrons.types import DeckSlotName @@ -18,6 +19,9 @@ ModuleModel, HeaterShakerLatchStatus, DeckType, + AddressableArea, + DeckConfigurationType, + PotentialCutoutFixture, ) from opentrons.protocol_engine.state.modules import ( @@ -37,6 +41,11 @@ ThermocyclerModuleSubState, ModuleSubStateType, ) + +from opentrons.protocol_engine.state.addressable_areas import ( + AddressableAreaView, + AddressableAreaState, +) from opentrons.protocol_engine.state.config import Config from opentrons.hardware_control.modules.types import LiveData @@ -48,9 +57,35 @@ ) +def get_addressable_area_view( + loaded_addressable_areas_by_name: Optional[Dict[str, AddressableArea]] = None, + potential_cutout_fixtures_by_cutout_id: Optional[ + Dict[str, Set[PotentialCutoutFixture]] + ] = None, + deck_definition: Optional[DeckDefinitionV5] = None, + deck_configuration: Optional[DeckConfigurationType] = None, + robot_type: RobotType = "OT-3 Standard", + use_simulated_deck_config: bool = False, +) -> AddressableAreaView: + """Get a labware view test subject.""" + state = AddressableAreaState( + loaded_addressable_areas_by_name=loaded_addressable_areas_by_name or {}, + potential_cutout_fixtures_by_cutout_id=potential_cutout_fixtures_by_cutout_id + or {}, + deck_definition=deck_definition or cast(DeckDefinitionV5, {"otId": "fake"}), + deck_configuration=deck_configuration or [], + robot_type=robot_type, + use_simulated_deck_config=use_simulated_deck_config, + ) + + return AddressableAreaView(state=state) + + def test_initial_state() -> None: """It should initialize the module state.""" - subject = ModuleStore(config=_OT2_STANDARD_CONFIG) + subject = ModuleStore( + config=_OT2_STANDARD_CONFIG, + ) assert subject.state == ModuleState( deck_type=DeckType.OT2_STANDARD, @@ -158,7 +193,9 @@ def test_load_module( ), ) - subject = ModuleStore(config=_OT2_STANDARD_CONFIG) + subject = ModuleStore( + config=_OT2_STANDARD_CONFIG, + ) subject.handle_action(action) assert subject.state == ModuleState( @@ -223,7 +260,7 @@ def test_load_thermocycler_in_thermocycler_slot( use_simulated_deck_config=False, robot_type=robot_type, deck_type=deck_type, - ) + ), ) subject.handle_action(action) @@ -302,7 +339,9 @@ def test_add_module_action( module_live_data=live_data, ) - subject = ModuleStore(_OT2_STANDARD_CONFIG) + subject = ModuleStore( + config=_OT2_STANDARD_CONFIG, + ) subject.handle_action(action) assert subject.state == ModuleState( @@ -343,7 +382,9 @@ def test_handle_hs_temperature_commands(heater_shaker_v1_def: ModuleDefinition) params=hs_commands.DeactivateHeaterParams(moduleId="module-id"), result=hs_commands.DeactivateHeaterResult(), ) - subject = ModuleStore(_OT2_STANDARD_CONFIG) + subject = ModuleStore( + config=_OT2_STANDARD_CONFIG, + ) subject.handle_action( actions.SucceedCommandAction(private_result=None, command=load_module_cmd) @@ -394,7 +435,9 @@ def test_handle_hs_shake_commands(heater_shaker_v1_def: ModuleDefinition) -> Non params=hs_commands.DeactivateShakerParams(moduleId="module-id"), result=hs_commands.DeactivateShakerResult(), ) - subject = ModuleStore(_OT2_STANDARD_CONFIG) + subject = ModuleStore( + config=_OT2_STANDARD_CONFIG, + ) subject.handle_action( actions.SucceedCommandAction(private_result=None, command=load_module_cmd) @@ -447,7 +490,9 @@ def test_handle_hs_labware_latch_commands( params=hs_commands.OpenLabwareLatchParams(moduleId="module-id"), result=hs_commands.OpenLabwareLatchResult(pipetteRetracted=False), ) - subject = ModuleStore(_OT2_STANDARD_CONFIG) + subject = ModuleStore( + config=_OT2_STANDARD_CONFIG, + ) subject.handle_action( actions.SucceedCommandAction(private_result=None, command=load_module_cmd) @@ -511,7 +556,9 @@ def test_handle_tempdeck_temperature_commands( params=temp_commands.DeactivateTemperatureParams(moduleId="module-id"), result=temp_commands.DeactivateTemperatureResult(), ) - subject = ModuleStore(_OT2_STANDARD_CONFIG) + subject = ModuleStore( + config=_OT2_STANDARD_CONFIG, + ) subject.handle_action( actions.SucceedCommandAction(private_result=None, command=load_module_cmd) @@ -570,7 +617,9 @@ def test_handle_thermocycler_temperature_commands( params=tc_commands.DeactivateLidParams(moduleId="module-id"), result=tc_commands.DeactivateLidResult(), ) - subject = ModuleStore(_OT2_STANDARD_CONFIG) + subject = ModuleStore( + config=_OT2_STANDARD_CONFIG, + ) subject.handle_action( actions.SucceedCommandAction(private_result=None, command=load_module_cmd) @@ -652,7 +701,7 @@ def test_handle_thermocycler_lid_commands( use_simulated_deck_config=False, robot_type="OT-3 Standard", deck_type=DeckType.OT3_STANDARD, - ) + ), ) subject.handle_action( diff --git a/api/tests/opentrons/protocol_engine/state/test_module_view.py b/api/tests/opentrons/protocol_engine/state/test_module_view.py index 77ab24bb336..b840673f2e8 100644 --- a/api/tests/opentrons/protocol_engine/state/test_module_view.py +++ b/api/tests/opentrons/protocol_engine/state/test_module_view.py @@ -4,7 +4,21 @@ from pytest_lazyfixture import lazy_fixture # type: ignore[import-untyped] from contextlib import nullcontext as does_not_raise -from typing import ContextManager, Dict, NamedTuple, Optional, Type, Union, Any, List +from typing import ( + ContextManager, + Dict, + NamedTuple, + Optional, + Type, + Union, + Any, + List, + Set, + cast, +) + +from opentrons_shared_data.robot.dev_types import RobotType +from opentrons_shared_data.deck.dev_types import DeckDefinitionV5 from opentrons_shared_data import load_shared_data from opentrons.types import DeckSlotName, MountType @@ -19,12 +33,19 @@ ModuleOffsetData, HeaterShakerLatchStatus, LabwareMovementOffsetData, + AddressableArea, + DeckConfigurationType, + PotentialCutoutFixture, ) from opentrons.protocol_engine.state.modules import ( ModuleView, ModuleState, HardwareModule, ) +from opentrons.protocol_engine.state.addressable_areas import ( + AddressableAreaView, + AddressableAreaState, +) from opentrons.protocol_engine.state.module_substates import ( HeaterShakerModuleSubState, @@ -37,6 +58,40 @@ ThermocyclerModuleId, ModuleSubStateType, ) +from opentrons_shared_data.deck import load as load_deck +from opentrons.protocols.api_support.deck_type import ( + STANDARD_OT3_DECK, +) + + +@pytest.fixture(scope="session") +def ot3_standard_deck_def() -> DeckDefinitionV5: + """Get the OT-2 standard deck definition.""" + return load_deck(STANDARD_OT3_DECK, 5) + + +def get_addressable_area_view( + loaded_addressable_areas_by_name: Optional[Dict[str, AddressableArea]] = None, + potential_cutout_fixtures_by_cutout_id: Optional[ + Dict[str, Set[PotentialCutoutFixture]] + ] = None, + deck_definition: Optional[DeckDefinitionV5] = None, + deck_configuration: Optional[DeckConfigurationType] = None, + robot_type: RobotType = "OT-3 Standard", + use_simulated_deck_config: bool = False, +) -> AddressableAreaView: + """Get a labware view test subject.""" + state = AddressableAreaState( + loaded_addressable_areas_by_name=loaded_addressable_areas_by_name or {}, + potential_cutout_fixtures_by_cutout_id=potential_cutout_fixtures_by_cutout_id + or {}, + deck_definition=deck_definition or cast(DeckDefinitionV5, {"otId": "fake"}), + deck_configuration=deck_configuration or [], + robot_type=robot_type, + use_simulated_deck_config=use_simulated_deck_config, + ) + + return AddressableAreaView(state=state) def make_module_view( @@ -332,41 +387,50 @@ def test_get_module_offset_for_ot2_standard( ) }, ) - assert subject.get_nominal_module_offset("module-id") == expected_offset + assert ( + subject.get_nominal_module_offset("module-id", get_addressable_area_view()) + == expected_offset + ) @pytest.mark.parametrize( - argnames=["module_def", "slot", "expected_offset"], + argnames=["module_def", "slot", "expected_offset", "deck_definition"], argvalues=[ ( lazy_fixture("tempdeck_v2_def"), DeckSlotName.SLOT_1.to_ot3_equivalent(), LabwareOffsetVector(x=0, y=0, z=9), + lazy_fixture("ot3_standard_deck_def"), ), ( lazy_fixture("tempdeck_v2_def"), DeckSlotName.SLOT_3.to_ot3_equivalent(), LabwareOffsetVector(x=0, y=0, z=9), + lazy_fixture("ot3_standard_deck_def"), ), ( lazy_fixture("thermocycler_v2_def"), DeckSlotName.SLOT_7.to_ot3_equivalent(), LabwareOffsetVector(x=-20.005, y=67.96, z=10.96), + lazy_fixture("ot3_standard_deck_def"), ), ( lazy_fixture("heater_shaker_v1_def"), DeckSlotName.SLOT_1.to_ot3_equivalent(), LabwareOffsetVector(x=0, y=0, z=18.95), + lazy_fixture("ot3_standard_deck_def"), ), ( lazy_fixture("heater_shaker_v1_def"), DeckSlotName.SLOT_3.to_ot3_equivalent(), LabwareOffsetVector(x=0, y=0, z=18.95), + lazy_fixture("ot3_standard_deck_def"), ), ( lazy_fixture("mag_block_v1_def"), - DeckSlotName.SLOT_2, + DeckSlotName.SLOT_2.to_ot3_equivalent(), LabwareOffsetVector(x=0, y=0, z=38.0), + lazy_fixture("ot3_standard_deck_def"), ), ], ) @@ -374,6 +438,7 @@ def test_get_module_offset_for_ot3_standard( module_def: ModuleDefinition, slot: DeckSlotName, expected_offset: LabwareOffsetVector, + deck_definition: DeckDefinitionV5, ) -> None: """It should return the correct labware offset for module in specified slot.""" subject = make_module_view( @@ -386,7 +451,16 @@ def test_get_module_offset_for_ot3_standard( ) }, ) - result_offset = subject.get_nominal_module_offset("module-id") + + result_offset = subject.get_nominal_module_offset( + "module-id", + get_addressable_area_view( + deck_configuration=None, + deck_definition=deck_definition, + use_simulated_deck_config=True, + ), + ) + assert (result_offset.x, result_offset.y, result_offset.z) == pytest.approx( (expected_offset.x, expected_offset.y, expected_offset.z) ) @@ -1767,10 +1841,20 @@ def test_get_default_gripper_offsets( @pytest.mark.parametrize( - argnames=["deck_type", "slot_name", "expected_highest_z"], + argnames=["deck_type", "slot_name", "expected_highest_z", "deck_definition"], argvalues=[ - (DeckType.OT2_STANDARD, DeckSlotName.SLOT_1, 84), - (DeckType.OT3_STANDARD, DeckSlotName.SLOT_D1, 12.91), + ( + DeckType.OT2_STANDARD, + DeckSlotName.SLOT_1, + 84, + lazy_fixture("ot3_standard_deck_def"), + ), + ( + DeckType.OT3_STANDARD, + DeckSlotName.SLOT_D1, + 12.91, + lazy_fixture("ot3_standard_deck_def"), + ), ], ) def test_get_module_highest_z( @@ -1778,6 +1862,7 @@ def test_get_module_highest_z( deck_type: DeckType, slot_name: DeckSlotName, expected_highest_z: float, + deck_definition: DeckDefinitionV5, ) -> None: """It should get the highest z point of the module.""" subject = make_module_view( @@ -1794,7 +1879,14 @@ def test_get_module_highest_z( }, ) assert isclose( - subject.get_module_highest_z(module_id="module-id"), + subject.get_module_highest_z( + module_id="module-id", + addressable_areas=get_addressable_area_view( + deck_configuration=None, + deck_definition=deck_definition, + use_simulated_deck_config=True, + ), + ), expected_highest_z, ) diff --git a/api/tests/opentrons/protocol_engine/state/test_state_store.py b/api/tests/opentrons/protocol_engine/state/test_state_store.py index 170f05bb4b9..b853b47733f 100644 --- a/api/tests/opentrons/protocol_engine/state/test_state_store.py +++ b/api/tests/opentrons/protocol_engine/state/test_state_store.py @@ -5,11 +5,11 @@ import pytest from decoy import Decoy -from opentrons_shared_data.deck.dev_types import DeckDefinitionV4 +from opentrons_shared_data.deck.dev_types import DeckDefinitionV5 +from opentrons.util.change_notifier import ChangeNotifier from opentrons.protocol_engine.actions import PlayAction from opentrons.protocol_engine.state import State, StateStore, Config -from opentrons.protocol_engine.state.change_notifier import ChangeNotifier from opentrons.protocol_engine.types import DeckType @@ -32,7 +32,7 @@ def engine_config() -> Config: @pytest.fixture def subject( change_notifier: ChangeNotifier, - ot2_standard_deck_def: DeckDefinitionV4, + ot2_standard_deck_def: DeckDefinitionV5, engine_config: Config, ) -> StateStore: """Get a StateStore test subject.""" diff --git a/api/tests/opentrons/protocol_engine/state/test_tip_state.py b/api/tests/opentrons/protocol_engine/state/test_tip_state.py index 25894554027..51f78c4904d 100644 --- a/api/tests/opentrons/protocol_engine/state/test_tip_state.py +++ b/api/tests/opentrons/protocol_engine/state/test_tip_state.py @@ -1121,17 +1121,17 @@ def _reconfigure_nozzle_layout(start: str, back_l: str, front_r: str) -> NozzleM ) return configure_nozzle_private_result.nozzle_map - map = _reconfigure_nozzle_layout("A1", "A1", "H10") - _assert_and_pickup("A3", map) + map = _reconfigure_nozzle_layout("A1", "A1", "H3") + _assert_and_pickup("A10", map) map = _reconfigure_nozzle_layout("A1", "A1", "F2") - _assert_and_pickup("C1", map) + _assert_and_pickup("C8", map) # Configure to single tip pickups map = _reconfigure_nozzle_layout("H12", "H12", "H12") _assert_and_pickup("A1", map) map = _reconfigure_nozzle_layout("H1", "H1", "H1") - _assert_and_pickup("A2", map) + _assert_and_pickup("A9", map) map = _reconfigure_nozzle_layout("A12", "A12", "A12") - _assert_and_pickup("B1", map) + _assert_and_pickup("H1", map) map = _reconfigure_nozzle_layout("A1", "A1", "A1") - _assert_and_pickup("B2", map) + _assert_and_pickup("B9", map) diff --git a/api/tests/opentrons/protocol_engine/test_create_protocol_engine.py b/api/tests/opentrons/protocol_engine/test_create_protocol_engine.py index b509946de75..2f7a0cae441 100644 --- a/api/tests/opentrons/protocol_engine/test_create_protocol_engine.py +++ b/api/tests/opentrons/protocol_engine/test_create_protocol_engine.py @@ -2,8 +2,9 @@ import pytest from pytest_lazyfixture import lazy_fixture # type: ignore[import-untyped] -from opentrons_shared_data.deck.dev_types import DeckDefinitionV4 +from opentrons_shared_data.deck.dev_types import DeckDefinitionV5 from opentrons_shared_data.robot.dev_types import RobotType +from opentrons_shared_data.deck import load as load_deck from opentrons.calibration_storage.helpers import uri_from_details from opentrons.hardware_control import API as HardwareAPI @@ -18,6 +19,30 @@ from opentrons.protocol_engine.types import DeckSlotLocation, LoadedLabware from opentrons.types import DeckSlotName +from opentrons.protocols.api_support.deck_type import ( + STANDARD_OT2_DECK, + SHORT_TRASH_DECK, + STANDARD_OT3_DECK, +) + + +@pytest.fixture(scope="session") +def ot2_standard_deck_def() -> DeckDefinitionV5: + """Get the OT-2 standard deck definition.""" + return load_deck(STANDARD_OT2_DECK, 5) + + +@pytest.fixture(scope="session") +def ot2_short_trash_deck_def() -> DeckDefinitionV5: + """Get the OT-2 with short trash standard deck definition.""" + return load_deck(SHORT_TRASH_DECK, 5) + + +@pytest.fixture(scope="session") +def ot3_standard_deck_def() -> DeckDefinitionV5: + """Get the OT-2 standard deck definition.""" + return load_deck(STANDARD_OT3_DECK, 5) + @pytest.mark.parametrize( ( @@ -47,7 +72,7 @@ async def test_create_engine_initializes_state_with_no_fixed_trash( hardware_api: HardwareAPI, robot_type: RobotType, deck_type: DeckType, - expected_deck_def: DeckDefinitionV4, + expected_deck_def: DeckDefinitionV5, ) -> None: """It should load deck geometry data into the store on create.""" engine = await create_protocol_engine( @@ -102,7 +127,7 @@ async def test_create_engine_initializes_state_with_fixed_trash( hardware_api: HardwareAPI, robot_type: RobotType, deck_type: DeckType, - expected_deck_def: DeckDefinitionV4, + expected_deck_def: DeckDefinitionV5, expected_fixed_trash_def: LabwareDefinition, expected_fixed_trash_slot: DeckSlotName, ) -> None: diff --git a/api/tests/opentrons/protocol_engine/test_protocol_engine.py b/api/tests/opentrons/protocol_engine/test_protocol_engine.py index dd96b8d968a..4816708fa57 100644 --- a/api/tests/opentrons/protocol_engine/test_protocol_engine.py +++ b/api/tests/opentrons/protocol_engine/test_protocol_engine.py @@ -8,9 +8,7 @@ from decoy import Decoy from opentrons_shared_data.robot.dev_types import RobotType -from opentrons.ordered_set import OrderedSet from opentrons.protocol_engine.actions.actions import ResumeFromRecoveryAction -from opentrons.protocol_engine.error_recovery_policy import ErrorRecoveryType from opentrons.types import DeckSlotName from opentrons.hardware_control import HardwareControlAPI, OT2HardwareControlAPI @@ -19,7 +17,9 @@ from opentrons.protocols.models import LabwareDefinition from opentrons.protocol_engine import ProtocolEngine, commands, slot_standardization -from opentrons.protocol_engine.errors.exceptions import EStopActivatedError +from opentrons.protocol_engine.errors.exceptions import ( + CommandNotAllowedError, +) from opentrons.protocol_engine.types import ( DeckType, LabwareOffset, @@ -59,7 +59,6 @@ QueueCommandAction, HardwareStoppedAction, ResetTipsAction, - FailCommandAction, ) @@ -130,9 +129,9 @@ def _mock_slot_standardization_module( def _mock_hash_command_params_module( decoy: Decoy, monkeypatch: pytest.MonkeyPatch ) -> None: - hash_command_params = commands.hash_command_params + hash_command_params = commands.hash_protocol_command_params monkeypatch.setattr( - commands, "hash_command_params", decoy.mock(func=hash_command_params) + commands, "hash_protocol_command_params", decoy.mock(func=hash_command_params) ) @@ -184,7 +183,9 @@ def test_add_command( original_request = commands.WaitForResumeCreate( params=commands.WaitForResumeParams() ) - standardized_request = commands.HomeCreate(params=commands.HomeParams()) + standardized_request = commands.HomeCreate( + params=commands.HomeParams(), intent=commands.CommandIntent.PROTOCOL + ) queued = commands.Home( id="command-id", key="command-key", @@ -204,9 +205,13 @@ def test_add_command( decoy.when(model_utils.generate_id()).then_return("command-id") decoy.when(model_utils.get_timestamp()).then_return(created_at) - decoy.when(state_store.commands.get_latest_command_hash()).then_return("abc") + decoy.when(state_store.commands.get_latest_protocol_command_hash()).then_return( + "abc" + ) decoy.when( - commands.hash_command_params(create=standardized_request, last_hash="abc") + commands.hash_protocol_command_params( + create=standardized_request, last_hash="abc" + ) ).then_return("123") def _stub_queued(*_a: object, **_k: object) -> None: @@ -246,6 +251,105 @@ def _stub_queued(*_a: object, **_k: object) -> None: assert result == queued +def test_add_fixit_command( + decoy: Decoy, + state_store: StateStore, + action_dispatcher: ActionDispatcher, + model_utils: ModelUtils, + subject: ProtocolEngine, +) -> None: + """It should add a fixit command to the state from a request.""" + created_at = datetime(year=2021, month=1, day=1) + original_request = commands.WaitForResumeCreate( + params=commands.WaitForResumeParams() + ) + standardized_request = commands.HomeCreate( + params=commands.HomeParams(), intent=commands.CommandIntent.FIXIT + ) + queued = commands.Home( + id="command-id", + key="command-key", + status=commands.CommandStatus.QUEUED, + createdAt=created_at, + params=commands.HomeParams(), + ) + + robot_type: RobotType = "OT-3 Standard" + decoy.when(state_store.config).then_return( + Config(robot_type=robot_type, deck_type=DeckType.OT3_STANDARD) + ) + + decoy.when( + slot_standardization.standardize_command(original_request, robot_type) + ).then_return(standardized_request) + + decoy.when(model_utils.generate_id()).then_return("command-id") + decoy.when(model_utils.get_timestamp()).then_return(created_at) + + def _stub_queued(*_a: object, **_k: object) -> None: + decoy.when(state_store.commands.get("command-id")).then_return(queued) + + decoy.when( + state_store.commands.validate_action_allowed( + QueueCommandAction( + command_id="command-id", + created_at=created_at, + request=standardized_request, + request_hash=None, + ) + ) + ).then_return( + QueueCommandAction( + command_id="command-id-validated", + created_at=created_at, + request=standardized_request, + request_hash=None, + ) + ) + + decoy.when( + action_dispatcher.dispatch( + QueueCommandAction( + command_id="command-id-validated", + created_at=created_at, + request=standardized_request, + request_hash=None, + ) + ), + ).then_do(_stub_queued) + + result = subject.add_command(original_request) + assert result == queued + + +def test_add_fixit_command_raises( + decoy: Decoy, + state_store: StateStore, + action_dispatcher: ActionDispatcher, + model_utils: ModelUtils, + subject: ProtocolEngine, +) -> None: + """It should raise if a failedCommandId is supplied without a fixit command.""" + original_request = commands.WaitForResumeCreate( + params=commands.WaitForResumeParams() + ) + standardized_request = commands.HomeCreate( + params=commands.HomeParams(), intent=commands.CommandIntent.PROTOCOL + ) + + robot_type: RobotType = "OT-3 Standard" + decoy.when(state_store.config).then_return( + Config(robot_type=robot_type, deck_type=DeckType.OT3_STANDARD) + ) + + decoy.when( + slot_standardization.standardize_command(original_request, robot_type) + ).then_return(standardized_request) + + with pytest.raises(CommandNotAllowedError): + subject.add_command(original_request, "id-123") + + async def test_add_and_execute_command( decoy: Decoy, state_store: StateStore, @@ -515,7 +619,7 @@ def test_pause( state_store.commands.validate_action_allowed(expected_action), ).then_return(expected_action) - subject.pause() + subject.request_pause() decoy.verify( action_dispatcher.dispatch(expected_action), @@ -570,8 +674,8 @@ async def test_finish( """It should be able to gracefully tell the engine it's done.""" completed_at = datetime(2021, 1, 1, 0, 0) - decoy.when(model_utils.get_timestamp()).then_return(completed_at) decoy.when(state_store.commands.state.stopped_by_estop).then_return(False) + decoy.when(model_utils.get_timestamp()).then_return(completed_at) await subject.finish( drop_tips_after_run=drop_tips_after_run, @@ -810,7 +914,7 @@ async def test_stop( state_store.commands.validate_action_allowed(expected_action), ).then_return(expected_action) - await subject.stop() + await subject.request_stop() decoy.verify( action_dispatcher.dispatch(expected_action), @@ -836,7 +940,7 @@ async def test_stop_for_legacy_core_protocols( decoy.when(hardware_api.is_movement_execution_taskified()).then_return(True) - await subject.stop() + await subject.request_stop() decoy.verify( action_dispatcher.dispatch(expected_action), @@ -845,106 +949,53 @@ async def test_stop_for_legacy_core_protocols( ) -@pytest.mark.parametrize("maintenance_run", [True, False]) -async def test_estop_during_command( +async def test_estop( decoy: Decoy, action_dispatcher: ActionDispatcher, queue_worker: QueueWorker, state_store: StateStore, subject: ProtocolEngine, - model_utils: ModelUtils, - maintenance_run: bool, ) -> None: """It should be able to stop the engine.""" - timestamp = datetime(2021, 1, 1, 0, 0) - command_id = "command_fake_id" - running_command = sentinel.running_command - queued_command = sentinel.queued_command - error_id = "fake_error_id" - fake_command_set = OrderedSet(["fake-id-1", "fake-id-1"]) - - decoy.when(model_utils.get_timestamp()).then_return(timestamp) - decoy.when(model_utils.generate_id()).then_return(error_id) - decoy.when(state_store.commands.get_is_stopped()).then_return(False) - decoy.when(state_store.commands.get_running_command_id()).then_return(command_id) - decoy.when(state_store.commands.get(command_id)).then_return(running_command) - decoy.when(state_store.commands.get_queue_ids()).then_return(fake_command_set) - decoy.when(state_store.commands.get(fake_command_set.head())).then_return( - queued_command - ) - - expected_action = FailCommandAction( - command_id=command_id, - running_command=running_command, - error_id=error_id, - failed_at=timestamp, - error=EStopActivatedError(message="Estop Activated"), - notes=[], - type=ErrorRecoveryType.FAIL_RUN, - ) - expected_action_2 = FailCommandAction( - command_id=fake_command_set.head(), - running_command=queued_command, - error_id=error_id, - failed_at=timestamp, - error=EStopActivatedError(message="Estop Activated"), - notes=[], - type=ErrorRecoveryType.FAIL_RUN, - ) - - subject.estop(maintenance_run=maintenance_run) + expected_action = StopAction(from_estop=True) + validated_action = sentinel.validated_action + decoy.when( + state_store.commands.validate_action_allowed(expected_action), + ).then_return(validated_action) + + subject.estop() decoy.verify( - action_dispatcher.dispatch(action=expected_action), - action_dispatcher.dispatch(action=expected_action_2), + action_dispatcher.dispatch(action=validated_action), queue_worker.cancel(), ) -@pytest.mark.parametrize("maintenance_run", [True, False]) -async def test_estop_without_command( +async def test_estop_noops_if_invalid( decoy: Decoy, action_dispatcher: ActionDispatcher, queue_worker: QueueWorker, state_store: StateStore, subject: ProtocolEngine, - model_utils: ModelUtils, - maintenance_run: bool, ) -> None: - """It should be able to stop the engine.""" - timestamp = datetime(2021, 1, 1, 0, 0) - error_id = "fake_error_id" - - decoy.when(model_utils.get_timestamp()).then_return(timestamp) - decoy.when(model_utils.generate_id()).then_return(error_id) - decoy.when(state_store.commands.get_is_stopped()).then_return(False) - decoy.when(state_store.commands.get_running_command_id()).then_return(None) - decoy.when(state_store.commands.get_queue_ids()).then_return(OrderedSet()) - - expected_stop = StopAction(from_estop=True) - expected_hardware_stop = HardwareStoppedAction( - completed_at=timestamp, - finish_error_details=FinishErrorDetails( - error=EStopActivatedError(message="Estop Activated"), - error_id=error_id, - created_at=timestamp, - ), - ) - + """It should no-op if a stop is invalid right now..""" + expected_action = StopAction(from_estop=True) decoy.when( - state_store.commands.validate_action_allowed(expected_stop), - ).then_return(expected_stop) + state_store.commands.validate_action_allowed(expected_action), + ).then_raise(RuntimeError("unable to stop; this machine craves flesh")) - subject.estop(maintenance_run=maintenance_run) + subject.estop() # Should not raise. decoy.verify( - action_dispatcher.dispatch(expected_stop), times=1 if maintenance_run else 0 + action_dispatcher.dispatch(), # type: ignore + ignore_extra_args=True, + times=0, ) decoy.verify( - action_dispatcher.dispatch(expected_hardware_stop), - times=1 if maintenance_run else 0, + queue_worker.cancel(), + ignore_extra_args=True, + times=0, ) - decoy.verify(queue_worker.cancel(), times=1 if maintenance_run else 0) def test_add_plugin( diff --git a/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_command_mapper.py b/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_command_mapper.py index 5d6595227b9..c8950cbe090 100644 --- a/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_command_mapper.py +++ b/api/tests/opentrons/protocol_runner/smoke_tests/test_legacy_command_mapper.py @@ -5,6 +5,7 @@ """ from datetime import datetime from pathlib import Path +from textwrap import dedent from typing import List import pytest @@ -753,3 +754,46 @@ async def test_zero_volume_dispense_commands( labwareId=load_well_plate.result.labwareId, wellName="D7", ) + + +async def test_air_gap(tmp_path: Path) -> None: + """An `air_gap()` should be mapped to an `aspirate`. + + This covers RQA-2621. + """ + path = tmp_path / "protocol.py" + path.write_text( + dedent( + """\ + metadata = {"apiLevel": "2.13"} + def run(protocol): + # Prep: + tip_rack = protocol.load_labware("opentrons_96_tiprack_300ul", 1) + well_plate = protocol.load_labware("biorad_96_wellplate_200ul_pcr", 2) + pipette = protocol.load_instrument("p300_single_gen2", mount="left", tip_racks=[tip_rack]) + pipette.pick_up_tip() + + # Test: + pipette.move_to(well_plate["A1"].top()) + pipette.air_gap(100) + """ + ) + ) + result_commands = await simulate_and_get_commands(path) + [ + initial_home, + load_tip_rack, + load_well_plate, + load_pipette, + pick_up_tip, + move_to_well, + air_gap_aspirate, + ] = result_commands + assert isinstance(initial_home, commands.Home) + assert isinstance(load_tip_rack, commands.LoadLabware) + assert isinstance(load_well_plate, commands.LoadLabware) + assert isinstance(load_pipette, commands.LoadPipette) + assert isinstance(pick_up_tip, commands.PickUpTip) + # TODO(mm, 2024-04-23): This commands.Custom looks wrong. This should be a commands.MoveToWell. + assert isinstance(move_to_well, commands.Custom) + assert isinstance(air_gap_aspirate, commands.Aspirate) diff --git a/api/tests/opentrons/protocol_runner/test_legacy_command_mapper.py b/api/tests/opentrons/protocol_runner/test_legacy_command_mapper.py index f0412878856..ada52714ee6 100644 --- a/api/tests/opentrons/protocol_runner/test_legacy_command_mapper.py +++ b/api/tests/opentrons/protocol_runner/test_legacy_command_mapper.py @@ -7,7 +7,13 @@ from decoy import matchers, Decoy from opentrons.hardware_control.dev_types import PipetteDict +from opentrons.hardware_control.modules.types import TemperatureModuleModel from opentrons.legacy_commands.types import CommentMessage, PauseMessage, CommandMessage +from opentrons.protocol_api.core.legacy.load_info import ( + LabwareLoadInfo as LegacyLabwareLoadInfo, + InstrumentLoadInfo as LegacyInstrumentLoadInfo, + ModuleLoadInfo as LegacyModuleLoadInfo, +) from opentrons.protocol_engine import ( DeckSlotLocation, ModuleLocation, @@ -29,12 +35,6 @@ LegacyCommandMapper, LegacyCommandParams, ) -from opentrons.protocol_runner.legacy_wrappers import ( - LegacyInstrumentLoadInfo, - LegacyLabwareLoadInfo, - LegacyModuleLoadInfo, - LegacyTemperatureModuleModel, -) from opentrons_shared_data.labware.dev_types import LabwareDefinition from opentrons_shared_data.module.dev_types import ModuleDefinitionV3 from opentrons_shared_data.pipette.dev_types import PipetteNameType @@ -396,8 +396,8 @@ def test_map_module_load( """It should correctly map a module load.""" test_definition = ModuleDefinition.parse_obj(minimal_module_def) input = LegacyModuleLoadInfo( - requested_model=LegacyTemperatureModuleModel.TEMPERATURE_V1, - loaded_model=LegacyTemperatureModuleModel.TEMPERATURE_V2, + requested_model=TemperatureModuleModel.TEMPERATURE_V1, + loaded_model=TemperatureModuleModel.TEMPERATURE_V2, deck_slot=DeckSlotName.SLOT_1, configuration="conf", module_serial="module-serial", @@ -579,6 +579,7 @@ def test_map_pause() -> None: "command.DISTRIBUTE", "command.TRANSFER", "command.RETURN_TIP", + "command.AIR_GAP", ], ) def test_filter_higher_order_commands(command_type: str) -> None: diff --git a/api/tests/opentrons/protocol_runner/test_legacy_context_plugin.py b/api/tests/opentrons/protocol_runner/test_legacy_context_plugin.py index f11676bcd37..368a34a297f 100644 --- a/api/tests/opentrons/protocol_runner/test_legacy_context_plugin.py +++ b/api/tests/opentrons/protocol_runner/test_legacy_context_plugin.py @@ -17,12 +17,10 @@ from opentrons.legacy_broker import LegacyBroker from opentrons.util.broker import ReadOnlyBroker +from opentrons.protocol_api.core.legacy.load_info import LoadInfo, LabwareLoadInfo + from opentrons.protocol_runner.legacy_command_mapper import LegacyCommandMapper from opentrons.protocol_runner.legacy_context_plugin import LegacyContextPlugin -from opentrons.protocol_runner.legacy_wrappers import ( - LegacyLoadInfo, - LegacyLabwareLoadInfo, -) from opentrons.types import DeckSlotName @@ -38,9 +36,9 @@ def mock_legacy_broker(decoy: Decoy) -> LegacyBroker: @pytest.fixture -def mock_equipment_broker(decoy: Decoy) -> ReadOnlyBroker[LegacyLoadInfo]: +def mock_equipment_broker(decoy: Decoy) -> ReadOnlyBroker[LoadInfo]: """Get a mocked out `equipment_broker: Broker` dependency.""" - return decoy.mock(cls=ReadOnlyBroker[LegacyLoadInfo]) + return decoy.mock(cls=ReadOnlyBroker[LoadInfo]) @pytest.fixture @@ -64,7 +62,7 @@ def mock_action_dispatcher(decoy: Decoy) -> pe_actions.ActionDispatcher: @pytest.fixture def subject( mock_legacy_broker: LegacyBroker, - mock_equipment_broker: ReadOnlyBroker[LegacyLoadInfo], + mock_equipment_broker: ReadOnlyBroker[LoadInfo], mock_legacy_command_mapper: LegacyCommandMapper, mock_state_view: StateView, mock_action_dispatcher: pe_actions.ActionDispatcher, @@ -92,7 +90,7 @@ def __exit__(self, type: object, value: object, traceback: object) -> None: async def test_broker_subscribe_unsubscribe( decoy: Decoy, mock_legacy_broker: LegacyBroker, - mock_equipment_broker: ReadOnlyBroker[LegacyLoadInfo], + mock_equipment_broker: ReadOnlyBroker[LoadInfo], subject: LegacyContextPlugin, ) -> None: """It should subscribe to the brokers on setup and unsubscribe on teardown.""" @@ -125,7 +123,7 @@ async def test_broker_subscribe_unsubscribe( async def test_command_broker_messages( decoy: Decoy, mock_legacy_broker: LegacyBroker, - mock_equipment_broker: ReadOnlyBroker[LegacyLoadInfo], + mock_equipment_broker: ReadOnlyBroker[LoadInfo], mock_legacy_command_mapper: LegacyCommandMapper, mock_action_dispatcher: pe_actions.ActionDispatcher, subject: LegacyContextPlugin, @@ -181,7 +179,7 @@ async def test_command_broker_messages( async def test_equipment_broker_messages( decoy: Decoy, mock_legacy_broker: LegacyBroker, - mock_equipment_broker: ReadOnlyBroker[LegacyLoadInfo], + mock_equipment_broker: ReadOnlyBroker[LoadInfo], mock_legacy_command_mapper: LegacyCommandMapper, mock_action_dispatcher: pe_actions.ActionDispatcher, subject: LegacyContextPlugin, @@ -199,9 +197,9 @@ async def test_equipment_broker_messages( subject.setup() - handler: Callable[[LegacyLabwareLoadInfo], None] = labware_handler_captor.value + handler: Callable[[LabwareLoadInfo], None] = labware_handler_captor.value - load_info = LegacyLabwareLoadInfo( + load_info = LabwareLoadInfo( labware_definition=minimal_labware_def, labware_namespace="some_namespace", labware_load_name="some_load_name", diff --git a/api/tests/opentrons/protocol_runner/test_protocol_runner.py b/api/tests/opentrons/protocol_runner/test_protocol_runner.py index 5497e9e12ab..6aa790bee98 100644 --- a/api/tests/opentrons/protocol_runner/test_protocol_runner.py +++ b/api/tests/opentrons/protocol_runner/test_protocol_runner.py @@ -8,15 +8,20 @@ from typing import List, cast, Optional, Union, Type from opentrons_shared_data.labware.labware_definition import LabwareDefinition +from opentrons_shared_data.labware.dev_types import ( + LabwareDefinition as LabwareDefinitionTypedDict, +) from opentrons_shared_data.protocol.models import ProtocolSchemaV6, ProtocolSchemaV7 from opentrons_shared_data.protocol.dev_types import ( JsonProtocol as LegacyJsonProtocolDict, ) from opentrons.hardware_control import API as HardwareAPI from opentrons.legacy_broker import LegacyBroker +from opentrons.protocol_api import ProtocolContext from opentrons.protocol_engine.types import PostRunHardwareState from opentrons.protocols.api_support.types import APIVersion from opentrons.protocols.parse import PythonParseMode +from opentrons.protocols.types import PythonProtocol, JsonProtocol from opentrons.util.broker import Broker from opentrons import protocol_reader @@ -42,14 +47,10 @@ from opentrons.protocol_runner.json_file_reader import JsonFileReader from opentrons.protocol_runner.json_translator import JsonTranslator from opentrons.protocol_runner.legacy_context_plugin import LegacyContextPlugin -from opentrons.protocol_runner.legacy_wrappers import ( - LegacyFileReader, - LegacyContextCreator, - LegacyExecutor, - LegacyPythonProtocol, - LegacyJsonProtocol, - LegacyProtocolContext, - LegacyLabwareDefinition, +from opentrons.protocol_runner.python_protocol_wrappers import ( + PythonAndLegacyFileReader, + ProtocolContextCreator, + PythonProtocolExecutor, ) @@ -84,21 +85,21 @@ def json_translator(decoy: Decoy) -> JsonTranslator: @pytest.fixture -def legacy_file_reader(decoy: Decoy) -> LegacyFileReader: - """Get a mocked out LegacyFileReader dependency.""" - return decoy.mock(cls=LegacyFileReader) +def python_and_legacy_file_reader(decoy: Decoy) -> PythonAndLegacyFileReader: + """Get a mocked out PythonAndLegacyFileReader dependency.""" + return decoy.mock(cls=PythonAndLegacyFileReader) @pytest.fixture -def legacy_context_creator(decoy: Decoy) -> LegacyContextCreator: - """Get a mocked out LegacyContextCreator dependency.""" - return decoy.mock(cls=LegacyContextCreator) +def protocol_context_creator(decoy: Decoy) -> ProtocolContextCreator: + """Get a mocked out ProtocolContextCreator dependency.""" + return decoy.mock(cls=ProtocolContextCreator) @pytest.fixture -def legacy_executor(decoy: Decoy) -> LegacyExecutor: - """Get a mocked out LegacyExecutor dependency.""" - return decoy.mock(cls=LegacyExecutor) +def python_protocol_executor(decoy: Decoy) -> PythonProtocolExecutor: + """Get a mocked out PythonProtocolExecutor dependency.""" + return decoy.mock(cls=PythonProtocolExecutor) @pytest.fixture(autouse=True) @@ -132,22 +133,22 @@ def json_runner_subject( @pytest.fixture -def legacy_python_runner_subject( +def python_runner_subject( protocol_engine: ProtocolEngine, hardware_api: HardwareAPI, task_queue: TaskQueue, - legacy_file_reader: LegacyFileReader, - legacy_context_creator: LegacyContextCreator, - legacy_executor: LegacyExecutor, + python_and_legacy_file_reader: PythonAndLegacyFileReader, + protocol_context_creator: ProtocolContextCreator, + python_protocol_executor: PythonProtocolExecutor, ) -> PythonAndLegacyRunner: """Get a PythonAndLegacyRunner test subject with mocked dependencies.""" return PythonAndLegacyRunner( protocol_engine=protocol_engine, hardware_api=hardware_api, task_queue=task_queue, - legacy_file_reader=legacy_file_reader, - legacy_context_creator=legacy_context_creator, - legacy_executor=legacy_executor, + python_and_legacy_file_reader=python_and_legacy_file_reader, + protocol_context_creator=protocol_context_creator, + python_protocol_executor=python_protocol_executor, ) @@ -182,9 +183,9 @@ def test_create_protocol_runner( task_queue: TaskQueue, json_file_reader: JsonFileReader, json_translator: JsonTranslator, - legacy_file_reader: LegacyFileReader, - legacy_context_creator: LegacyContextCreator, - legacy_executor: LegacyExecutor, + python_and_legacy_file_reader: PythonAndLegacyFileReader, + protocol_context_creator: ProtocolContextCreator, + python_protocol_executor: PythonProtocolExecutor, config: Optional[Union[JsonProtocolConfig, PythonProtocolConfig]], runner_type: Type[AnyRunner], ) -> None: @@ -206,7 +207,7 @@ def test_create_protocol_runner( "subject", [ (lazy_fixture("json_runner_subject")), - (lazy_fixture("legacy_python_runner_subject")), + (lazy_fixture("python_runner_subject")), (lazy_fixture("live_runner_subject")), ], ) @@ -226,7 +227,7 @@ def test_play_starts_run( "subject", [ (lazy_fixture("json_runner_subject")), - (lazy_fixture("legacy_python_runner_subject")), + (lazy_fixture("python_runner_subject")), (lazy_fixture("live_runner_subject")), ], ) @@ -238,14 +239,14 @@ def test_pause( """It should pause a protocol run with pause.""" subject.pause() - decoy.verify(protocol_engine.pause(), times=1) + decoy.verify(protocol_engine.request_pause(), times=1) @pytest.mark.parametrize( "subject", [ (lazy_fixture("json_runner_subject")), - (lazy_fixture("legacy_python_runner_subject")), + (lazy_fixture("python_runner_subject")), (lazy_fixture("live_runner_subject")), ], ) @@ -261,14 +262,14 @@ async def test_stop( subject.play() await subject.stop() - decoy.verify(await protocol_engine.stop(), times=1) + decoy.verify(await protocol_engine.request_stop(), times=1) @pytest.mark.parametrize( "subject", [ (lazy_fixture("json_runner_subject")), - (lazy_fixture("legacy_python_runner_subject")), + (lazy_fixture("python_runner_subject")), (lazy_fixture("live_runner_subject")), ], ) @@ -297,7 +298,7 @@ async def test_stop_when_run_never_started( "subject", [ (lazy_fixture("json_runner_subject")), - (lazy_fixture("legacy_python_runner_subject")), + (lazy_fixture("python_runner_subject")), (lazy_fixture("live_runner_subject")), ], ) @@ -521,12 +522,12 @@ async def test_load_json_runner( async def test_load_legacy_python( decoy: Decoy, - legacy_file_reader: LegacyFileReader, - legacy_context_creator: LegacyContextCreator, - legacy_executor: LegacyExecutor, + python_and_legacy_file_reader: PythonAndLegacyFileReader, + protocol_context_creator: ProtocolContextCreator, + python_protocol_executor: PythonProtocolExecutor, task_queue: TaskQueue, protocol_engine: ProtocolEngine, - legacy_python_runner_subject: PythonAndLegacyRunner, + python_runner_subject: PythonAndLegacyRunner, ) -> None: """It should load a legacy context-based Python protocol.""" labware_definition = LabwareDefinition.construct() # type: ignore[call-arg] @@ -541,9 +542,9 @@ async def test_load_legacy_python( content_hash="abc123", ) - extra_labware = {"definition-uri": cast(LegacyLabwareDefinition, {})} + extra_labware = {"definition-uri": cast(LabwareDefinitionTypedDict, {})} - legacy_protocol = LegacyPythonProtocol( + legacy_protocol = PythonProtocol( text="", contents="", filename="protocol.py", @@ -556,13 +557,13 @@ async def test_load_legacy_python( extra_labware=extra_labware, ) - legacy_context = decoy.mock(cls=LegacyProtocolContext) + protocol_context = decoy.mock(cls=ProtocolContext) decoy.when( await protocol_reader.extract_labware_definitions(legacy_protocol_source) ).then_return([labware_definition]) decoy.when( - legacy_file_reader.read( + python_and_legacy_file_reader.read( protocol_source=legacy_protocol_source, labware_definitions=[labware_definition], python_parse_mode=PythonParseMode.ALLOW_LEGACY_METADATA_AND_REQUIREMENTS, @@ -570,14 +571,14 @@ async def test_load_legacy_python( ).then_return(legacy_protocol) broker_captor = matchers.Captor() decoy.when( - legacy_context_creator.create( + protocol_context_creator.create( protocol=legacy_protocol, broker=broker_captor, equipment_broker=matchers.IsA(Broker), ) - ).then_return(legacy_context) + ).then_return(protocol_context) - await legacy_python_runner_subject.load( + await python_runner_subject.load( legacy_protocol_source, python_parse_mode=PythonParseMode.ALLOW_LEGACY_METADATA_AND_REQUIREMENTS, run_time_param_values=None, @@ -591,7 +592,7 @@ async def test_load_legacy_python( task_queue.set_run_func(run_func_captor), ) - assert broker_captor.value is legacy_python_runner_subject.broker + assert broker_captor.value is python_runner_subject.broker # Verify that the run func calls the right things: run_func = run_func_captor.value @@ -600,10 +601,10 @@ async def test_load_legacy_python( await protocol_engine.add_and_execute_command( request=pe_commands.HomeCreate(params=pe_commands.HomeParams(axes=None)) ), - await legacy_executor.execute( + await python_protocol_executor.execute( protocol=legacy_protocol, - context=legacy_context, - parameter_context=legacy_python_runner_subject._parameter_context, + context=protocol_context, + parameter_context=python_runner_subject._parameter_context, run_time_param_values=None, ), ) @@ -611,13 +612,13 @@ async def test_load_legacy_python( async def test_load_python_with_pe_papi_core( decoy: Decoy, - legacy_file_reader: LegacyFileReader, - legacy_context_creator: LegacyContextCreator, + python_and_legacy_file_reader: PythonAndLegacyFileReader, + protocol_context_creator: ProtocolContextCreator, protocol_engine: ProtocolEngine, - legacy_python_runner_subject: PythonAndLegacyRunner, + python_runner_subject: PythonAndLegacyRunner, ) -> None: """It should load a legacy context-based Python protocol.""" - legacy_protocol_source = ProtocolSource( + protocol_source = ProtocolSource( directory=Path("/dev/null"), main_file=Path("/dev/null/abc.py"), files=[], @@ -627,7 +628,7 @@ async def test_load_python_with_pe_papi_core( content_hash="abc123", ) - legacy_protocol = LegacyPythonProtocol( + protocol = PythonProtocol( text="", contents="", filename="protocol.py", @@ -640,43 +641,43 @@ async def test_load_python_with_pe_papi_core( extra_labware=None, ) - legacy_context = decoy.mock(cls=LegacyProtocolContext) + protocol_context = decoy.mock(cls=ProtocolContext) decoy.when( - await protocol_reader.extract_labware_definitions(legacy_protocol_source) + await protocol_reader.extract_labware_definitions(protocol_source) ).then_return([]) decoy.when( - legacy_file_reader.read( - protocol_source=legacy_protocol_source, + python_and_legacy_file_reader.read( + protocol_source=protocol_source, labware_definitions=[], python_parse_mode=PythonParseMode.ALLOW_LEGACY_METADATA_AND_REQUIREMENTS, ) - ).then_return(legacy_protocol) + ).then_return(protocol) broker_captor = matchers.Captor() decoy.when( - legacy_context_creator.create( - protocol=legacy_protocol, broker=broker_captor, equipment_broker=None + protocol_context_creator.create( + protocol=protocol, broker=broker_captor, equipment_broker=None ) - ).then_return(legacy_context) + ).then_return(protocol_context) - await legacy_python_runner_subject.load( - legacy_protocol_source, + await python_runner_subject.load( + protocol_source, python_parse_mode=PythonParseMode.ALLOW_LEGACY_METADATA_AND_REQUIREMENTS, run_time_param_values=None, ) decoy.verify(protocol_engine.add_plugin(matchers.IsA(LegacyContextPlugin)), times=0) - assert broker_captor.value is legacy_python_runner_subject.broker + assert broker_captor.value is python_runner_subject.broker async def test_load_legacy_json( decoy: Decoy, - legacy_file_reader: LegacyFileReader, - legacy_context_creator: LegacyContextCreator, - legacy_executor: LegacyExecutor, + python_and_legacy_file_reader: PythonAndLegacyFileReader, + protocol_context_creator: ProtocolContextCreator, + python_protocol_executor: PythonProtocolExecutor, task_queue: TaskQueue, protocol_engine: ProtocolEngine, - legacy_python_runner_subject: PythonAndLegacyRunner, + python_runner_subject: PythonAndLegacyRunner, ) -> None: """It should load a legacy context-based JSON protocol.""" labware_definition = LabwareDefinition.construct() # type: ignore[call-arg] @@ -691,7 +692,7 @@ async def test_load_legacy_json( content_hash="abc123", ) - legacy_protocol = LegacyJsonProtocol( + legacy_protocol = JsonProtocol( text="{}", contents=cast(LegacyJsonProtocolDict, {}), filename="protocol.json", @@ -701,27 +702,27 @@ async def test_load_legacy_json( metadata={"protocolName": "A Very Impressive Protocol"}, ) - legacy_context = decoy.mock(cls=LegacyProtocolContext) + protocol_context = decoy.mock(cls=ProtocolContext) decoy.when( await protocol_reader.extract_labware_definitions(legacy_protocol_source) ).then_return([labware_definition]) decoy.when( - legacy_file_reader.read( + python_and_legacy_file_reader.read( protocol_source=legacy_protocol_source, labware_definitions=[labware_definition], python_parse_mode=PythonParseMode.ALLOW_LEGACY_METADATA_AND_REQUIREMENTS, ) ).then_return(legacy_protocol) decoy.when( - legacy_context_creator.create( + protocol_context_creator.create( legacy_protocol, broker=matchers.IsA(LegacyBroker), equipment_broker=matchers.IsA(Broker), ) - ).then_return(legacy_context) + ).then_return(protocol_context) - await legacy_python_runner_subject.load( + await python_runner_subject.load( legacy_protocol_source, python_parse_mode=PythonParseMode.ALLOW_LEGACY_METADATA_AND_REQUIREMENTS, run_time_param_values=None, @@ -742,10 +743,10 @@ async def test_load_legacy_json( await protocol_engine.add_and_execute_command( request=pe_commands.HomeCreate(params=pe_commands.HomeParams(axes=None)) ), - await legacy_executor.execute( + await python_protocol_executor.execute( protocol=legacy_protocol, - context=legacy_context, - parameter_context=legacy_python_runner_subject._parameter_context, + context=protocol_context, + parameter_context=python_runner_subject._parameter_context, run_time_param_values=None, ), ) @@ -756,16 +757,16 @@ async def test_run_python_runner( hardware_api: HardwareAPI, protocol_engine: ProtocolEngine, task_queue: TaskQueue, - legacy_python_runner_subject: PythonAndLegacyRunner, + python_runner_subject: PythonAndLegacyRunner, ) -> None: """It should run a protocol to completion.""" decoy.when(protocol_engine.state_view.commands.has_been_played()).then_return( False, True ) - assert legacy_python_runner_subject.was_started() is False - await legacy_python_runner_subject.run(deck_configuration=[]) - assert legacy_python_runner_subject.was_started() is True + assert python_runner_subject.was_started() is False + await python_runner_subject.run(deck_configuration=[]) + assert python_runner_subject.was_started() is True decoy.verify( protocol_engine.play(deck_configuration=[]), diff --git a/api/tests/opentrons/protocols/parameters/test_validation.py b/api/tests/opentrons/protocols/parameters/test_validation.py index 1f092a51c46..0ff337eb91d 100644 --- a/api/tests/opentrons/protocols/parameters/test_validation.py +++ b/api/tests/opentrons/protocols/parameters/test_validation.py @@ -12,6 +12,14 @@ from opentrons.protocols.parameters import validation as subject +def test_validate_variable_name_unique() -> None: + """It should no-op if the name is unique or if it's not a string, and raise if it is not.""" + subject.validate_variable_name_unique("one of a kind", {"fee", "foo", "fum"}) + subject.validate_variable_name_unique({}, {"fee", "foo", "fum"}) # type: ignore[arg-type] + with pytest.raises(ParameterNameError): + subject.validate_variable_name_unique("copy", {"paste", "copy", "cut"}) + + def test_ensure_display_name() -> None: """It should ensure the display name is within the character limit.""" result = subject.ensure_display_name("abc") @@ -96,10 +104,12 @@ def test_ensure_variable_name_raises_keyword(variable_name: str) -> None: def test_validate_options() -> None: """It should not raise when given valid constraints""" subject.validate_options(123, 1, 100, None, int) + subject.validate_options(123, 100, 100, None, int) subject.validate_options( 123, None, None, [{"display_name": "abc", "value": 456}], int ) subject.validate_options(12.3, 1.1, 100.9, None, float) + subject.validate_options(12.3, 1.1, 1.1, None, float) subject.validate_options( 12.3, None, None, [{"display_name": "abc", "value": 45.6}], float ) @@ -271,14 +281,15 @@ def test_convert_type_string_for_num_param_raises(param_type: type) -> None: None, [{"display_name": "abc", "value": "123"}], int, - "must match type", + "must be of type", ), (123, 1, None, None, int, "maximum must also"), (123, None, 100, None, int, "minimum must also"), (123, 100, 1, None, int, "Maximum must be greater"), - (123, 1.1, 100, None, int, "Minimum and maximum must match type"), - (123, 1, 100.5, None, int, "Minimum and maximum must match type"), - (123, "1", "100", None, int, "Only parameters of type float or int"), + (123, 1.1, 100, None, int, "Minimum is type"), + (123, 1, 100.5, None, int, "Maximum is type"), + (123.0, "1.0", 100.0, None, float, "Minimum is type"), + ("blah", 1, 100, None, str, "Only parameters of type float or int"), ], ) def test_validate_options_raise_definition_error( diff --git a/robot-server/tests/service/notifications/test_change_notifier.py b/api/tests/opentrons/util/test_change_notifier.py similarity index 88% rename from robot-server/tests/service/notifications/test_change_notifier.py rename to api/tests/opentrons/util/test_change_notifier.py index 4967e6d254e..7ab9f3d9013 100644 --- a/robot-server/tests/service/notifications/test_change_notifier.py +++ b/api/tests/opentrons/util/test_change_notifier.py @@ -1,7 +1,7 @@ """Tests for the ChangeNotifier interface.""" import asyncio import pytest -from opentrons.protocol_engine.state.change_notifier import ChangeNotifier +from opentrons.util.change_notifier import ChangeNotifier async def test_single_subscriber() -> None: @@ -24,12 +24,12 @@ async def test_multiple_subscribers(_test_repetition: int) -> None: """Test that multiple subscribers can wait for a notification. This test checks that the subscribers are awoken in the order they - subscribed. This may or may not be guarenteed according to the + subscribed. This may or may not be guaranteed according to the implementations of both ChangeNotifier and the event loop. - This test functions as a canary, given that our code may relies + This test functions as a canary, given that our code may rely on this ordering for determinism. - This test runs multiple times to check for flakyness. + This test runs multiple times to check for flakiness. """ subject = ChangeNotifier() results = [] diff --git a/api/tests/opentrons/util/test_performance_helpers.py b/api/tests/opentrons/util/test_performance_helpers.py new file mode 100644 index 00000000000..57a42ef6a71 --- /dev/null +++ b/api/tests/opentrons/util/test_performance_helpers.py @@ -0,0 +1,28 @@ +"""Tests for performance_helpers.""" + +from pathlib import Path +from opentrons_shared_data.performance.dev_types import RobotContextState +from opentrons.util.performance_helpers import ( + StubbedTracker, + _get_robot_context_tracker, +) + + +def test_return_function_unchanged() -> None: + """Test that the function is returned unchanged when using StubbedTracker.""" + tracker = StubbedTracker(Path("/path/to/storage"), True) + + def func_to_track() -> None: + pass + + assert ( + tracker.track(RobotContextState.ANALYZING_PROTOCOL)(func_to_track) + is func_to_track + ) + + +def test_singleton_tracker() -> None: + """Test that the tracker is a singleton.""" + tracker = _get_robot_context_tracker() + tracker2 = _get_robot_context_tracker() + assert tracker is tracker2 diff --git a/app-shell-odd/src/config/__fixtures__/index.ts b/app-shell-odd/src/config/__fixtures__/index.ts index 5e26ddc99ef..b3ff0cbfbd7 100644 --- a/app-shell-odd/src/config/__fixtures__/index.ts +++ b/app-shell-odd/src/config/__fixtures__/index.ts @@ -11,11 +11,13 @@ import type { ConfigV21, } from '@opentrons/app/src/redux/config/types' +const PKG_VERSION: string = _PKG_VERSION_ + export const MOCK_CONFIG_V12: ConfigV12 = { version: 12, devtools: false, reinstallDevtools: false, - update: { channel: _PKG_VERSION_.includes('beta') ? 'beta' : 'latest' }, + update: { channel: PKG_VERSION.includes('beta') ? 'beta' : 'latest' }, log: { level: { file: 'debug', console: 'info' } }, ui: { width: 1024, diff --git a/app-shell-odd/src/config/migrate.ts b/app-shell-odd/src/config/migrate.ts index 6d9a1c9b82b..9a05df79594 100644 --- a/app-shell-odd/src/config/migrate.ts +++ b/app-shell-odd/src/config/migrate.ts @@ -22,11 +22,12 @@ import type { const CONFIG_VERSION_LATEST = 21 // update this after each config version bump +const PKG_VERSION: string = _PKG_VERSION_ export const DEFAULTS_V12: ConfigV12 = { version: 12, devtools: false, reinstallDevtools: false, - update: { channel: _PKG_VERSION_.includes('beta') ? 'beta' : 'latest' }, + update: { channel: PKG_VERSION.includes('beta') ? 'beta' : 'latest' }, log: { level: { file: 'debug', console: 'info' } }, ui: { width: 1024, diff --git a/app-shell-odd/src/update.ts b/app-shell-odd/src/update.ts index f27ce2eced4..d1ea2f154b3 100644 --- a/app-shell-odd/src/update.ts +++ b/app-shell-odd/src/update.ts @@ -14,15 +14,15 @@ import type { ReleaseSetUrls } from './system-update/types' const log = createLogger('update') +const OPENTRONS_PROJECT: string = _OPENTRONS_PROJECT_ + export const FLEX_MANIFEST_URL = - // @ts-expect-error can't get TS to recognize global.d.ts - global._OPENTRONS_PROJECT_ && - // @ts-expect-error can't get TS to recognize global.d.ts - global._OPENTRONS_PROJECT_.includes('robot-stack') + OPENTRONS_PROJECT && OPENTRONS_PROJECT.includes('robot-stack') ? 'https://builds.opentrons.com/ot3-oe/releases.json' : 'https://ot3-development.builds.opentrons.com/ot3-oe/releases.json' -let LATEST_OT_SYSTEM_VERSION = _PKG_VERSION_ +const PKG_VERSION = _PKG_VERSION_ +let LATEST_OT_SYSTEM_VERSION = PKG_VERSION const channelFinder = (version: string, channel: string): boolean => { // return the latest alpha/beta if a user subscribes to alpha/beta updates @@ -60,7 +60,7 @@ export const updateLatestVersion = (): Promise => { }) .find(verson => channelFinder(verson, channel)) const changed = LATEST_OT_SYSTEM_VERSION !== latestAvailableVersion - LATEST_OT_SYSTEM_VERSION = latestAvailableVersion ?? _PKG_VERSION_ + LATEST_OT_SYSTEM_VERSION = latestAvailableVersion ?? PKG_VERSION if (changed) { log.info( `Update: latest version available from ${FLEX_MANIFEST_URL} is ${latestAvailableVersion}` @@ -80,7 +80,7 @@ export const getLatestVersion = (): string => { return LATEST_OT_SYSTEM_VERSION } -export const getCurrentVersion = (): string => _PKG_VERSION_ +export const getCurrentVersion = (): string => PKG_VERSION export const isUpdateAvailable = (): boolean => getLatestVersion() !== getCurrentVersion() diff --git a/app-shell-odd/typings/global.d.ts b/app-shell-odd/typings/global.d.ts index 8513596d045..3b470870c2b 100644 --- a/app-shell-odd/typings/global.d.ts +++ b/app-shell-odd/typings/global.d.ts @@ -1,11 +1,4 @@ -import type { IpcRenderer } from 'electron' - declare global { - const _PKG_VERSION_: string - const _PKG_PRODUCT_NAME_: string - const _PKG_BUGS_URL_: string - const _OPENTRONS_PROJECT_: string - namespace NodeJS { export interface Global { APP_SHELL_REMOTE: { @@ -14,3 +7,8 @@ declare global { } } } + +declare const _PKG_VERSION_: string +declare const _PKG_PRODUCT_NAME_: string +declare const _PKG_BUGS_URL_: string +declare const _OPENTRONS_PROJECT_: string diff --git a/app-shell-odd/vite.config.ts b/app-shell-odd/vite.config.ts index b9575159675..7848c92bd8d 100644 --- a/app-shell-odd/vite.config.ts +++ b/app-shell-odd/vite.config.ts @@ -1,13 +1,14 @@ -import { versionForProject } from '../scripts/git-version' +import { versionForProject } from '../scripts/git-version.mjs' import pkg from './package.json' import path from 'path' -import { UserConfig, defineConfig } from 'vite' +import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import postCssImport from 'postcss-import' import postCssApply from 'postcss-apply' import postColorModFunction from 'postcss-color-mod-function' import postCssPresetEnv from 'postcss-preset-env' import lostCss from 'lost' +import type { UserConfig } from 'vite' export default defineConfig( async (): Promise => { @@ -79,7 +80,7 @@ export default defineConfig( '../discovery-client/src/index.ts' ), '@opentrons/usb-bridge/node-client': path.resolve( - '../usb-bridge/node-client/src/inxex.ts' + '../usb-bridge/node-client/src/index.ts' ), }, }, diff --git a/app-shell/Makefile b/app-shell/Makefile index 96e5dd73902..88bbf74b9ad 100644 --- a/app-shell/Makefile +++ b/app-shell/Makefile @@ -109,6 +109,7 @@ package-deps: clean lib deps package dist-posix dist-osx dist-linux dist-win: export NODE_ENV := production package dist-posix dist-osx dist-linux dist-win: export BUILD_ID := $(build_id) package dist-posix dist-osx dist-linux dist-win: export NO_PYTHON := $(if $(no_python_bundle),true,false) +package dist-posix dist-osx dist-linux dist-win: export USE_HARD_LINKS := false .PHONY: package package: package-deps @@ -170,18 +171,16 @@ _dist-collect-artifacts: # development ##################################################################### -.PHONY: clean-dev-autoupdate -clean-dev-autoupdate: - rm -f ./dev-app-update.yml -dev-app-update.yml: +.PHONY: dev-app-update-file +dev-app-update-file: cp ./dev-app-update-$(OPENTRONS_PROJECT).yml ./dev-app-update.yml .PHONY: dev dev: export NODE_ENV := development dev: export OPENTRONS_PROJECT := $(OPENTRONS_PROJECT) -dev: clean-dev-autoupdate ./dev-app-update.yml +dev: dev-app-update-file vite build $(electron) diff --git a/app-shell/build/release-notes-internal.md b/app-shell/build/release-notes-internal.md index a15d877c0ab..e6925397157 100644 --- a/app-shell/build/release-notes-internal.md +++ b/app-shell/build/release-notes-internal.md @@ -1,6 +1,50 @@ For more details about this release, please see the full [technical changelog][]. [technical change log]: https://github.com/Opentrons/opentrons/releases +## Internal Release 1.5.0-alpha.1 + +This internal release is from the `edge` branch to contain rapid dev on new features for 7.3.0. This release is for internal testing purposes and if used may require a factory reset of the robot to return to a stable version. + + + +--- + +## Internal Release 1.5.0-alpha.0 + +This internal release is from the `edge` branch to contain rapid dev on new features for 7.3.0. This release is for internal testing purposes and if used may require a factory reset of the robot to return to a stable version. + + + +--- + +## Internal Release 1.4.0-alpha.1 + +This internal release is from the `edge` branch to contain rapid dev on new features for 7.3.0. This release is for internal testing purposes and if used may require a factory reset of the robot to return to a stable version. + +### Notable bug fixes + +App and robot update prompts should now function properly. However, updating from 1.4.0-alpha.0 to 1.4.0-alpha.1 will still present issues, as the fix is not in 1.4.0-alpha.0. After installing 1.4.0-alpha.1, switch your update channel to "latest" to receive the latest stable internal release prompt, which validates the fix. + +### All changes + + + +--- + +## Internal Release 1.4.0-alpha.0 + +This internal release is from the `edge` branch to contain rapid dev on new features for 7.3.0. This release is for internal testing purposes and if used may require a factory reset of the robot to return to a stable version. + + + +--- + +## Internal Release 1.3.0-alpha.0 + +This internal release is from the `edge` branch to contain rapid dev on new features for 7.3.0. This release is for internal testing purposes and if used may require a factory reset of the robot to return to a stable version. + + + --- # Internal Release 1.1.0 diff --git a/app-shell/build/release-notes.md b/app-shell/build/release-notes.md index 97fa5f01b81..3234103cd1a 100644 --- a/app-shell/build/release-notes.md +++ b/app-shell/build/release-notes.md @@ -6,6 +6,50 @@ log][]. For a list of currently known issues, please see the [Opentrons issue tr --- +## Opentrons App Changes in 7.3.0 + +Welcome to the v7.3.0 release of the Opentrons App! This release adds support for Python protocols with runtime parameters, letting you change the behavior of a protocol each time you run it. + +Note: After updating, the app will prompt you to reanalyze all previously imported protocols. This is a one-time step and should not affect protocol behavior. + +### New Features + +Runtime Parameters + +- Available runtime parameters are shown on the protocol details screen. +- Both the Opentrons App and touchscreen let you enter new parameter values during run setup. +- The app highlights changed parameter values so you can confirm them before starting the run. +- The run preview (before the run) and run log (after the run) reflect changes to steps based on your chosen parameter values. + +Modules in Deck Configuration + +- You can now specify what slots modules occupy on Flex in deck configuration. +- When moving, Flex will avoid modules specified in deck configuration but not loaded in the protocol. +- Deck configuration must be compatible with the protocol's requirements before you start a run. + +### Improved Features + +- Lists of robots are now sorted alphabetically. + +### Removals + +- Removed the "Use older protocol analysis method" advanced setting for OT-2. If you need this type of analysis, use `opentrons_simulate` on the command line. + +### Bug Fixes + +- All run log steps now appear in the same font size. +- The app now properly sends custom labware definitions, along with the corresponding Python protocol, to Flex robots connected via USB. + +--- + +## Opentrons App Changes in 7.2.2 + +Welcome to the v7.2.2 release of the Opentrons App! + +There are no changes to the Opentrons App in v7.2.2, but it is required for updating the robot software to improve some features. + +--- + ## Opentrons App Changes in 7.2.1 Welcome to the v7.2.1 release of the Opentrons App! diff --git a/app-shell/dev-app-update-robot-stack.yml b/app-shell/dev-app-update-robot-stack.yml index 9edb1ccde11..0561f4592d7 100644 --- a/app-shell/dev-app-update-robot-stack.yml +++ b/app-shell/dev-app-update-robot-stack.yml @@ -1,3 +1,3 @@ provider: generic -bucket: https://builds.opentrons.com/app/ +url: https://builds.opentrons.com/app/ channel: latest diff --git a/app-shell/electron-builder.config.js b/app-shell/electron-builder.config.js index 727b2d5e900..aa61720338b 100644 --- a/app-shell/electron-builder.config.js +++ b/app-shell/electron-builder.config.js @@ -1,6 +1,5 @@ 'use strict' const path = require('path') -const { versionForProject } = require('../scripts/git-version') const { OT_APP_DEPLOY_BUCKET, @@ -45,7 +44,9 @@ module.exports = async () => ({ }, ], extraMetadata: { - version: await versionForProject(project), + version: await ( + await import('../scripts/git-version.mjs') + ).versionForProject(project), productName: project === 'robot-stack' ? 'Opentrons' : 'Opentrons-OT3', }, extraResources: USE_PYTHON ? ['python'] : [], diff --git a/app-shell/src/main.ts b/app-shell/src/main.ts index 75f301fa718..1f44b0607b9 100644 --- a/app-shell/src/main.ts +++ b/app-shell/src/main.ts @@ -4,7 +4,6 @@ import electronDebug from 'electron-debug' import dns from 'dns' import contextMenu from 'electron-context-menu' import * as electronDevtoolsInstaller from 'electron-devtools-installer' -import { webusb } from 'usb' import { createUi, registerReloadUi } from './ui' import { initializeMenu } from './menu' @@ -18,7 +17,6 @@ import { registerSystemInfo } from './system-info' import { registerProtocolStorage } from './protocol-storage' import { getConfig, getStore, getOverrides, registerConfig } from './config' import { registerUsb } from './usb' -import { createUsbDeviceMonitor } from './system-info/usb-devices' import { registerNotify, closeAllNotifyConnections } from './notifications' import type { BrowserWindow } from 'electron' @@ -57,8 +55,6 @@ if (config.devtools) app.once('ready', installDevtools) app.once('window-all-closed', () => { log.debug('all windows closed, quitting the app') - webusb.removeEventListener('connect', () => createUsbDeviceMonitor()) - webusb.removeEventListener('disconnect', () => createUsbDeviceMonitor()) app.quit() closeAllNotifyConnections() .then(() => { @@ -77,8 +73,6 @@ function startUp(): void { log.error('Uncaught Promise rejection: ', { reason }) ) - webusb.addEventListener('connect', () => createUsbDeviceMonitor()) - webusb.addEventListener('disconnect', () => createUsbDeviceMonitor()) mainWindow = createUi() rendererLogger = createRendererLogger() diff --git a/app-shell/src/menu.ts b/app-shell/src/menu.ts index 71b1318df38..52f04978934 100644 --- a/app-shell/src/menu.ts +++ b/app-shell/src/menu.ts @@ -5,6 +5,9 @@ import type { MenuItemConstructorOptions } from 'electron' import { LOG_DIR } from './log' +const PRODUCT_NAME: string = _PKG_PRODUCT_NAME_ +const BUGS_URL: string = _PKG_BUGS_URL_ + // file or application menu const firstMenu: MenuItemConstructorOptions = { role: process.platform === 'darwin' ? 'appMenu' : 'fileMenu', @@ -27,8 +30,7 @@ const helpMenu: MenuItemConstructorOptions = { }, }, { - // @ts-expect-error can't get TS to recognize global.d.ts - label: `View ${global._PKG_PRODUCT_NAME_} App Logs`, + label: `View ${PRODUCT_NAME} App Logs`, click: () => { shell.openPath(LOG_DIR) }, @@ -37,8 +39,7 @@ const helpMenu: MenuItemConstructorOptions = { label: 'Report an Issue', click: () => { // eslint-disable-next-line @typescript-eslint/no-floating-promises - // @ts-expect-error can't get TS to recognize global.d.ts - shell.openExternal(global._PKG_BUGS_URL_) + shell.openExternal(BUGS_URL) }, }, ], diff --git a/app-shell/src/protocol-storage/index.ts b/app-shell/src/protocol-storage/index.ts index 7c202e9be92..53ec7148861 100644 --- a/app-shell/src/protocol-storage/index.ts +++ b/app-shell/src/protocol-storage/index.ts @@ -1,7 +1,6 @@ import fse from 'fs-extra' import path from 'path' import { shell } from 'electron' -import first from 'lodash/first' import { ADD_PROTOCOL, @@ -48,18 +47,6 @@ export const getParsedAnalysisFromPath = ( } } -export const getProtocolSrcFilePaths = ( - protocolKey: string -): Promise => { - const protocolDir = `${FileSystem.PROTOCOLS_DIRECTORY_PATH}/${protocolKey}` - return ensureDir(protocolDir) - .then(() => FileSystem.parseProtocolDirs([protocolDir])) - .then(storedProtocols => { - const storedProtocol = first(storedProtocols) - return storedProtocol?.srcFilePaths ?? [] - }) -} - // Revert a v7.0.0 pre-parity stop-gap solution. const migrateProtocolsFromTempDirectory = preParityMigrateProtocolsFrom( FileSystem.PRE_V7_PARITY_DIRECTORY_PATH, diff --git a/app-shell/src/robot-update/constants.ts b/app-shell/src/robot-update/constants.ts index 48f8ef8e611..22a494d07d7 100644 --- a/app-shell/src/robot-update/constants.ts +++ b/app-shell/src/robot-update/constants.ts @@ -4,6 +4,8 @@ import type { UpdateManifestUrls } from './types' import type { RobotUpdateTarget } from '@opentrons/app/src/redux/robot-update/types' import { CURRENT_VERSION } from '../update' +const OPENTRONS_PROJECT: string = _OPENTRONS_PROJECT_ + const UPDATE_MANIFEST_URLS_RELEASE = { ot2: 'https://builds.opentrons.com/ot2-br/releases.json', flex: 'https://builds.opentrons.com/ot3-oe/releases.json', @@ -15,8 +17,7 @@ const UPDATE_MANIFEST_URLS_INTERNAL_RELEASE = { } export const getUpdateManifestUrls = (): UpdateManifestUrls => - // @ts-expect-error can't get TS to recognize global.d.ts - global._OPENTRONS_PROJECT_.includes('robot-stack') + OPENTRONS_PROJECT.includes('robot-stack') ? UPDATE_MANIFEST_URLS_RELEASE : UPDATE_MANIFEST_URLS_INTERNAL_RELEASE diff --git a/app-shell/src/usb.ts b/app-shell/src/usb.ts index d9edd69ef25..accdf5c00d7 100644 --- a/app-shell/src/usb.ts +++ b/app-shell/src/usb.ts @@ -1,8 +1,6 @@ import { ipcMain, IpcMainInvokeEvent } from 'electron' import axios, { AxiosRequestConfig } from 'axios' import FormData from 'form-data' -import fs from 'fs' -import path from 'path' import { fetchSerialPortList, @@ -12,7 +10,6 @@ import { } from '@opentrons/usb-bridge/node-client' import { createLogger } from './log' -import { getProtocolSrcFilePaths } from './protocol-storage' import { usbRequestsStart, usbRequestsStop } from './config/actions' import { SYSTEM_INFO_INITIALIZED, @@ -20,6 +17,7 @@ import { USB_DEVICE_REMOVED, } from './constants' +import type { IPCSafeFormData } from '@opentrons/app/src/redux/shell/types' import type { UsbDevice } from '@opentrons/app/src/redux/system-info/types' import type { PortInfo } from '@opentrons/usb-bridge/node-client' import type { Action, Dispatch } from './types' @@ -83,6 +81,17 @@ function isUsbDeviceOt3(device: UsbDevice): boolean { device.vendorId === parseInt(DEFAULT_VENDOR_ID, 16) ) } + +function reconstructFormData(ipcSafeFormData: IPCSafeFormData): FormData { + const result = new FormData() + ipcSafeFormData.forEach(entry => { + entry.type === 'file' + ? result.append(entry.name, Buffer.from(entry.value), entry.filename) + : result.append(entry.name, entry.value) + }) + return result +} + async function usbListener( _event: IpcMainInvokeEvent, config: AxiosRequestConfig @@ -92,21 +101,9 @@ async function usbListener( let formHeaders = {} // check for formDataProxy - if (data?.formDataProxy != null) { + if (data?.proxiedFormData != null) { // reconstruct FormData - const formData = new FormData() - const { protocolKey } = data.formDataProxy - - const srcFilePaths: string[] = await getProtocolSrcFilePaths(protocolKey) - - // create readable stream from file - srcFilePaths.forEach(srcFilePath => { - const readStream = fs.createReadStream(srcFilePath) - formData.append('files', readStream, path.basename(srcFilePath)) - }) - - formData.append('key', protocolKey) - + const formData = reconstructFormData(data.proxiedFormData) formHeaders = formData.getHeaders() data = formData } diff --git a/app-shell/typings/global.d.ts b/app-shell/typings/global.d.ts index 8bdea90e637..67f9a5a1955 100644 --- a/app-shell/typings/global.d.ts +++ b/app-shell/typings/global.d.ts @@ -1,8 +1,9 @@ /* eslint-disable no-var */ declare global { - var _PKG_VERSION_: string - var _PKG_PRODUCT_NAME_: string - var _PKG_BUGS_URL_: string - var _OPENTRONS_PROJECT_: string var APP_SHELL_REMOTE: { ipcRenderer: IpcRenderer; [key: string]: any } } + +declare const _PKG_VERSION_: string +declare const _PKG_PRODUCT_NAME_: string +declare const _PKG_BUGS_URL_: string +declare const _OPENTRONS_PROJECT_: string diff --git a/app-shell/vite.config.ts b/app-shell/vite.config.ts index 80ca80b0aa4..546fe19e23f 100644 --- a/app-shell/vite.config.ts +++ b/app-shell/vite.config.ts @@ -1,7 +1,8 @@ -import { versionForProject } from '../scripts/git-version' +import { versionForProject } from '../scripts/git-version.mjs' import pkg from './package.json' import path from 'path' -import { UserConfig, defineConfig } from 'vite' +import { defineConfig } from 'vite' +import type { UserConfig } from 'vite' export default defineConfig( async (): Promise => { diff --git a/app-testing/.gitignore b/app-testing/.gitignore index 8c771199b29..6ae4921e11a 100644 --- a/app-testing/.gitignore +++ b/app-testing/.gitignore @@ -1,3 +1,5 @@ .env results analysis_results/*.json +files/protocols/generated_protocols/* +!files/protocols/generated_protocols/.keepme diff --git a/app-testing/Makefile b/app-testing/Makefile index 40abbc0e7aa..e1d9698d3cb 100644 --- a/app-testing/Makefile +++ b/app-testing/Makefile @@ -8,26 +8,26 @@ black-check: .PHONY: ruff ruff: - python -m pipenv run python -m ruff . --fix --unsafe-fixes + python -m pipenv run python -m ruff check . --fix .PHONY: ruff-check ruff-check: - python -m pipenv run python -m ruff . + python -m pipenv run python -m ruff check . .PHONY: mypy mypy: python -m pipenv run python -m mypy conftest.py automation tests citools .PHONY: lint -lint: - $(MAKE) black-check - $(MAKE) ruff-check - $(MAKE) mypy +lint: black-check ruff-check mypy .PHONY: format -format: +format: + @echo runnning black $(MAKE) black + @echo running ruff $(MAKE) ruff + @echo formatting the readme with yarn prettier $(MAKE) format-readme .PHONY: test-ci @@ -50,10 +50,6 @@ teardown: format-readme: yarn prettier --ignore-path .eslintignore --write app-testing/**/*.md -.PHONY: print-protocols -print-protocols: - python -m pipenv run python print_protocols.py - .PHONY: install-pipenv install-pipenv: python -m pip install -U pipenv @@ -67,9 +63,15 @@ snapshot-test-update: python -m pipenv run pytest -k analyses_snapshot_test --snapshot-update TARGET ?= edge +CACHEBUST := $(shell date +%s) .PHONY: build-opentrons-analysis build-opentrons-analysis: @echo "Building docker image for $(TARGET)" - @echo "If you want to build a different version, run 'make build-docker TARGET='" - docker build --build-arg OPENTRONS_VERSION=$(TARGET) -t opentrons-analysis:$(TARGET) citools/. + @echo "If you want to build a different version, run 'make build-opentrons-analysis TARGET='" + @echo "Cache is always busted to ensure latest version of the code is used" + docker build --build-arg OPENTRONS_VERSION=$(TARGET) --build-arg CACHEBUST=$(CACHEBUST) -t opentrons-analysis:$(TARGET) citools/. + +.PHONY: generate-protocols +generate-protocols: + python -m pipenv run python -m automation.data.protocol_registry diff --git a/app-testing/Pipfile b/app-testing/Pipfile index 6b584a7fb4a..43bb4dd2475 100644 --- a/app-testing/Pipfile +++ b/app-testing/Pipfile @@ -4,23 +4,19 @@ url = "https://pypi.org/simple" verify_ssl = true [packages] -pytest = "==7.4.3" -black = "==23.11.0" -selenium = "==4.15.2" -importlib-metadata = "==6.8.0" +pytest = "==8.1.1" +black = "==24.3.0" +selenium = "==4.19.0" +importlib-metadata = "==7.1.0" requests = "==2.31.0" -python-dotenv = "==1.0.0" -pytest-xdist = "==3.5.0" -mypy = "==1.7.1" -types-requests = "==2.31.0.10" -rich = "==13.7.0" -atomicwrites = "==1.4.1" -pyreadline3 = "==3.4.1" -pydantic = "==2.5.2" -pygithub = "==2.1.1" -ruff = "==0.1.6" -docker = "==6.1.3" -syrupy = "==4.6.0" +python-dotenv = "==1.0.1" +mypy = "==1.9.0" +types-requests = "==2.31.0.20240311" +rich = "==13.7.1" +pydantic = "==2.6.4" +ruff = "==0.3.4" +docker = "==7.0.0" +syrupy = "==4.6.1" pytest-html = "==4.1.1" [requires] diff --git a/app-testing/Pipfile.lock b/app-testing/Pipfile.lock index e6d0c62ad48..0672556f9cd 100644 --- a/app-testing/Pipfile.lock +++ b/app-testing/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "833b9fb969bfaeeae450d8fdff72fe005f8b2857541ba692965d2177ff6004de" + "sha256": "b7ac4510c6e3aa343c669e1bd838183e905abb6f1701c6efbfb1c22f20cfae44" }, "pipfile-spec": 6, "requires": { @@ -24,111 +24,50 @@ "markers": "python_version >= '3.8'", "version": "==0.6.0" }, - "atomicwrites": { - "hashes": [ - "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11" - ], - "index": "pypi", - "version": "==1.4.1" - }, "attrs": { "hashes": [ - "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04", - "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015" + "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", + "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" ], "markers": "python_version >= '3.7'", - "version": "==23.1.0" + "version": "==23.2.0" }, "black": { "hashes": [ - "sha256:250d7e60f323fcfc8ea6c800d5eba12f7967400eb6c2d21ae85ad31c204fb1f4", - "sha256:2a9acad1451632021ee0d146c8765782a0c3846e0e0ea46659d7c4f89d9b212b", - "sha256:412f56bab20ac85927f3a959230331de5614aecda1ede14b373083f62ec24e6f", - "sha256:421f3e44aa67138ab1b9bfbc22ee3780b22fa5b291e4db8ab7eee95200726b07", - "sha256:45aa1d4675964946e53ab81aeec7a37613c1cb71647b5394779e6efb79d6d187", - "sha256:4c44b7211a3a0570cc097e81135faa5f261264f4dfaa22bd5ee2875a4e773bd6", - "sha256:4c68855825ff432d197229846f971bc4d6666ce90492e5b02013bcaca4d9ab05", - "sha256:5133f5507007ba08d8b7b263c7aa0f931af5ba88a29beacc4b2dc23fcefe9c06", - "sha256:54caaa703227c6e0c87b76326d0862184729a69b73d3b7305b6288e1d830067e", - "sha256:58e5f4d08a205b11800332920e285bd25e1a75c54953e05502052738fe16b3b5", - "sha256:698c1e0d5c43354ec5d6f4d914d0d553a9ada56c85415700b81dc90125aac244", - "sha256:6c1cac07e64433f646a9a838cdc00c9768b3c362805afc3fce341af0e6a9ae9f", - "sha256:760415ccc20f9e8747084169110ef75d545f3b0932ee21368f63ac0fee86b221", - "sha256:7f622b6822f02bfaf2a5cd31fdb7cd86fcf33dab6ced5185c35f5db98260b055", - "sha256:cf57719e581cfd48c4efe28543fea3d139c6b6f1238b3f0102a9c73992cbb479", - "sha256:d136ef5b418c81660ad847efe0e55c58c8208b77a57a28a503a5f345ccf01394", - "sha256:dbea0bb8575c6b6303cc65017b46351dc5953eea5c0a59d7b7e3a2d2f433a911", - "sha256:fc7f6a44d52747e65a02558e1d807c82df1d66ffa80a601862040a43ec2e3142" + "sha256:2818cf72dfd5d289e48f37ccfa08b460bf469e67fb7c4abb07edc2e9f16fb63f", + "sha256:41622020d7120e01d377f74249e677039d20e6344ff5851de8a10f11f513bf93", + "sha256:4acf672def7eb1725f41f38bf6bf425c8237248bb0804faa3965c036f7672d11", + "sha256:4be5bb28e090456adfc1255e03967fb67ca846a03be7aadf6249096100ee32d0", + "sha256:4f1373a7808a8f135b774039f61d59e4be7eb56b2513d3d2f02a8b9365b8a8a9", + "sha256:56f52cfbd3dabe2798d76dbdd299faa046a901041faf2cf33288bc4e6dae57b5", + "sha256:65b76c275e4c1c5ce6e9870911384bff5ca31ab63d19c76811cb1fb162678213", + "sha256:65c02e4ea2ae09d16314d30912a58ada9a5c4fdfedf9512d23326128ac08ac3d", + "sha256:6905238a754ceb7788a73f02b45637d820b2f5478b20fec82ea865e4f5d4d9f7", + "sha256:79dcf34b33e38ed1b17434693763301d7ccbd1c5860674a8f871bd15139e7837", + "sha256:7bb041dca0d784697af4646d3b62ba4a6b028276ae878e53f6b4f74ddd6db99f", + "sha256:7d5e026f8da0322b5662fa7a8e752b3fa2dac1c1cbc213c3d7ff9bdd0ab12395", + "sha256:9f50ea1132e2189d8dff0115ab75b65590a3e97de1e143795adb4ce317934995", + "sha256:a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f", + "sha256:aadf7a02d947936ee418777e0247ea114f78aff0d0959461057cae8a04f20597", + "sha256:b5991d523eee14756f3c8d5df5231550ae8993e2286b8014e2fdea7156ed0959", + "sha256:bf21b7b230718a5f08bd32d5e4f1db7fc8788345c8aea1d155fc17852b3410f5", + "sha256:c45f8dff244b3c431b36e3224b6be4a127c6aca780853574c00faf99258041eb", + "sha256:c7ed6668cbbfcd231fa0dc1b137d3e40c04c7f786e626b405c62bcd5db5857e4", + "sha256:d7de8d330763c66663661a1ffd432274a2f92f07feeddd89ffd085b5744f85e7", + "sha256:e19cb1c6365fd6dc38a6eae2dcb691d7d83935c10215aef8e6c38edee3f77abd", + "sha256:e2af80566f43c85f5797365077fb64a393861a3730bd110971ab7a0c94e873e7" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==23.11.0" + "version": "==24.3.0" }, "certifi": { "hashes": [ - "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1", - "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474" + "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", + "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" ], "markers": "python_version >= '3.6'", - "version": "==2023.11.17" - }, - "cffi": { - "hashes": [ - "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc", - "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a", - "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417", - "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab", - "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520", - "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36", - "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743", - "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8", - "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed", - "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684", - "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56", - "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324", - "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d", - "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235", - "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e", - "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088", - "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000", - "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7", - "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e", - "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673", - "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c", - "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe", - "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2", - "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098", - "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8", - "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a", - "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0", - "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b", - "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896", - "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e", - "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9", - "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2", - "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b", - "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6", - "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404", - "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f", - "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0", - "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4", - "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc", - "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936", - "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba", - "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872", - "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb", - "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614", - "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1", - "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d", - "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969", - "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b", - "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4", - "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627", - "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956", - "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357" - ], - "markers": "python_version >= '3.8'", - "version": "==1.16.0" + "version": "==2024.2.2" }, "charset-normalizer": { "hashes": [ @@ -234,58 +173,14 @@ "markers": "python_version >= '3.7'", "version": "==8.1.7" }, - "cryptography": { - "hashes": [ - "sha256:079b85658ea2f59c4f43b70f8119a52414cdb7be34da5d019a77bf96d473b960", - "sha256:09616eeaef406f99046553b8a40fbf8b1e70795a91885ba4c96a70793de5504a", - "sha256:13f93ce9bea8016c253b34afc6bd6a75993e5c40672ed5405a9c832f0d4a00bc", - "sha256:37a138589b12069efb424220bf78eac59ca68b95696fc622b6ccc1c0a197204a", - "sha256:3c78451b78313fa81607fa1b3f1ae0a5ddd8014c38a02d9db0616133987b9cdf", - "sha256:43f2552a2378b44869fe8827aa19e69512e3245a219104438692385b0ee119d1", - "sha256:48a0476626da912a44cc078f9893f292f0b3e4c739caf289268168d8f4702a39", - "sha256:49f0805fc0b2ac8d4882dd52f4a3b935b210935d500b6b805f321addc8177406", - "sha256:5429ec739a29df2e29e15d082f1d9ad683701f0ec7709ca479b3ff2708dae65a", - "sha256:5a1b41bc97f1ad230a41657d9155113c7521953869ae57ac39ac7f1bb471469a", - "sha256:68a2dec79deebc5d26d617bfdf6e8aab065a4f34934b22d3b5010df3ba36612c", - "sha256:7a698cb1dac82c35fcf8fe3417a3aaba97de16a01ac914b89a0889d364d2f6be", - "sha256:841df4caa01008bad253bce2a6f7b47f86dc9f08df4b433c404def869f590a15", - "sha256:90452ba79b8788fa380dfb587cca692976ef4e757b194b093d845e8d99f612f2", - "sha256:928258ba5d6f8ae644e764d0f996d61a8777559f72dfeb2eea7e2fe0ad6e782d", - "sha256:af03b32695b24d85a75d40e1ba39ffe7db7ffcb099fe507b39fd41a565f1b157", - "sha256:b640981bf64a3e978a56167594a0e97db71c89a479da8e175d8bb5be5178c003", - "sha256:c5ca78485a255e03c32b513f8c2bc39fedb7f5c5f8535545bdc223a03b24f248", - "sha256:c7f3201ec47d5207841402594f1d7950879ef890c0c495052fa62f58283fde1a", - "sha256:d5ec85080cce7b0513cfd233914eb8b7bbd0633f1d1703aa28d1dd5a72f678ec", - "sha256:d6c391c021ab1f7a82da5d8d0b3cee2f4b2c455ec86c8aebbc84837a631ff309", - "sha256:e3114da6d7f95d2dee7d3f4eec16dacff819740bbab931aff8648cb13c5ff5e7", - "sha256:f983596065a18a2183e7f79ab3fd4c475205b839e02cbc0efbbf9666c4b3083d" - ], - "version": "==41.0.7" - }, - "deprecated": { - "hashes": [ - "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c", - "sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.2.14" - }, "docker": { "hashes": [ - "sha256:aa6d17830045ba5ef0168d5eaa34d37beeb113948c413affe1d5991fc11f9a20", - "sha256:aecd2277b8bf8e506e484f6ab7aec39abe0038e29fa4a6d3ba86c3fe01844ed9" + "sha256:12ba681f2777a0ad28ffbcc846a69c31b4dfd9752b47eb425a274ee269c5e14b", + "sha256:323736fb92cd9418fc5e7133bc953e11a9da04f4483f828b527db553f1e7e5a3" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==6.1.3" - }, - "execnet": { - "hashes": [ - "sha256:88256416ae766bc9e8895c76a87928c0012183da3cc4fc18016e6f050e025f41", - "sha256:cc59bc4423742fd71ad227122eb0dd44db51efb3dc4095b45ac9a08c770096af" - ], - "markers": "python_version >= '3.7'", - "version": "==2.0.2" + "markers": "python_version >= '3.8'", + "version": "==7.0.0" }, "h11": { "hashes": [ @@ -305,12 +200,12 @@ }, "importlib-metadata": { "hashes": [ - "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb", - "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743" + "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570", + "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==6.8.0" + "version": "==7.1.0" }, "iniconfig": { "hashes": [ @@ -322,11 +217,11 @@ }, "jinja2": { "hashes": [ - "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", - "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" + "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa", + "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90" ], "markers": "python_version >= '3.7'", - "version": "==3.1.2" + "version": "==3.1.3" }, "markdown-it-py": { "hashes": [ @@ -338,69 +233,69 @@ }, "markupsafe": { "hashes": [ - "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e", - "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e", - "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431", - "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686", - "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c", - "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559", - "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc", - "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb", - "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939", - "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c", - "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0", - "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4", - "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9", - "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575", - "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba", - "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d", - "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd", - "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3", - "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00", - "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155", - "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac", - "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52", - "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f", - "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8", - "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b", - "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007", - "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24", - "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea", - "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198", - "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0", - "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee", - "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be", - "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2", - "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1", - "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707", - "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6", - "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c", - "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58", - "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823", - "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779", - "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636", - "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c", - "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad", - "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee", - "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc", - "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2", - "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48", - "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7", - "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e", - "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b", - "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa", - "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5", - "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e", - "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb", - "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9", - "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57", - "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc", - "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc", - "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2", - "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11" + "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf", + "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff", + "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f", + "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3", + "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532", + "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f", + "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617", + "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df", + "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4", + "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906", + "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f", + "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", + "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8", + "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371", + "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2", + "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465", + "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52", + "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6", + "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", + "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad", + "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", + "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0", + "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029", + "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", + "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a", + "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", + "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5", + "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c", + "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf", + "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9", + "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", + "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", + "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3", + "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", + "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46", + "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc", + "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a", + "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", + "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900", + "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5", + "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea", + "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", + "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5", + "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e", + "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a", + "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f", + "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50", + "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", + "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", + "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4", + "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff", + "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2", + "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46", + "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", + "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf", + "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", + "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5", + "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab", + "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd", + "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68" ], "markers": "python_version >= '3.7'", - "version": "==2.1.3" + "version": "==2.1.5" }, "mdurl": { "hashes": [ @@ -412,37 +307,37 @@ }, "mypy": { "hashes": [ - "sha256:12cce78e329838d70a204293e7b29af9faa3ab14899aec397798a4b41be7f340", - "sha256:1484b8fa2c10adf4474f016e09d7a159602f3239075c7bf9f1627f5acf40ad49", - "sha256:204e0d6de5fd2317394a4eff62065614c4892d5a4d1a7ee55b765d7a3d9e3f82", - "sha256:2643d145af5292ee956aa0a83c2ce1038a3bdb26e033dadeb2f7066fb0c9abce", - "sha256:2c6e4464ed5f01dc44dc9821caf67b60a4e5c3b04278286a85c067010653a0eb", - "sha256:2f7f6985d05a4e3ce8255396df363046c28bea790e40617654e91ed580ca7c51", - "sha256:31902408f4bf54108bbfb2e35369877c01c95adc6192958684473658c322c8a5", - "sha256:40716d1f821b89838589e5b3106ebbc23636ffdef5abc31f7cd0266db936067e", - "sha256:4b901927f16224d0d143b925ce9a4e6b3a758010673eeded9b748f250cf4e8f7", - "sha256:4fc3d14ee80cd22367caaaf6e014494415bf440980a3045bf5045b525680ac33", - "sha256:5cf3f0c5ac72139797953bd50bc6c95ac13075e62dbfcc923571180bebb662e9", - "sha256:6dbdec441c60699288adf051f51a5d512b0d818526d1dcfff5a41f8cd8b4aaf1", - "sha256:72cf32ce7dd3562373f78bd751f73c96cfb441de147cc2448a92c1a308bd0ca6", - "sha256:75aa828610b67462ffe3057d4d8a4112105ed211596b750b53cbfe182f44777a", - "sha256:75c4d2a6effd015786c87774e04331b6da863fc3fc4e8adfc3b40aa55ab516fe", - "sha256:78e25b2fd6cbb55ddfb8058417df193f0129cad5f4ee75d1502248e588d9e0d7", - "sha256:84860e06ba363d9c0eeabd45ac0fde4b903ad7aa4f93cd8b648385a888e23200", - "sha256:8c5091ebd294f7628eb25ea554852a52058ac81472c921150e3a61cdd68f75a7", - "sha256:944bdc21ebd620eafefc090cdf83158393ec2b1391578359776c00de00e8907a", - "sha256:9c7ac372232c928fff0645d85f273a726970c014749b924ce5710d7d89763a28", - "sha256:d9b338c19fa2412f76e17525c1b4f2c687a55b156320acb588df79f2e6fa9fea", - "sha256:ee5d62d28b854eb61889cde4e1dbc10fbaa5560cb39780c3995f6737f7e82120", - "sha256:f2c2521a8e4d6d769e3234350ba7b65ff5d527137cdcde13ff4d99114b0c8e7d", - "sha256:f6efc9bd72258f89a3816e3a98c09d36f079c223aa345c659622f056b760ab42", - "sha256:f7c5d642db47376a0cc130f0de6d055056e010debdaf0707cd2b0fc7e7ef30ea", - "sha256:fcb6d9afb1b6208b4c712af0dafdc650f518836065df0d4fb1d800f5d6773db2", - "sha256:fcd2572dd4519e8a6642b733cd3a8cfc1ef94bafd0c1ceed9c94fe736cb65b6a" + "sha256:0235391f1c6f6ce487b23b9dbd1327b4ec33bb93934aa986efe8a9563d9349e6", + "sha256:190da1ee69b427d7efa8aa0d5e5ccd67a4fb04038c380237a0d96829cb157913", + "sha256:2418488264eb41f69cc64a69a745fad4a8f86649af4b1041a4c64ee61fc61129", + "sha256:3a3c007ff3ee90f69cf0a15cbcdf0995749569b86b6d2f327af01fd1b8aee9dc", + "sha256:3cc5da0127e6a478cddd906068496a97a7618a21ce9b54bde5bf7e539c7af974", + "sha256:48533cdd345c3c2e5ef48ba3b0d3880b257b423e7995dada04248725c6f77374", + "sha256:49c87c15aed320de9b438ae7b00c1ac91cd393c1b854c2ce538e2a72d55df150", + "sha256:4d3dbd346cfec7cb98e6cbb6e0f3c23618af826316188d587d1c1bc34f0ede03", + "sha256:571741dc4194b4f82d344b15e8837e8c5fcc462d66d076748142327626a1b6e9", + "sha256:587ce887f75dd9700252a3abbc9c97bbe165a4a630597845c61279cf32dfbf02", + "sha256:5d741d3fc7c4da608764073089e5f58ef6352bedc223ff58f2f038c2c4698a89", + "sha256:5e6061f44f2313b94f920e91b204ec600982961e07a17e0f6cd83371cb23f5c2", + "sha256:61758fabd58ce4b0720ae1e2fea5cfd4431591d6d590b197775329264f86311d", + "sha256:653265f9a2784db65bfca694d1edd23093ce49740b2244cde583aeb134c008f3", + "sha256:68edad3dc7d70f2f17ae4c6c1b9471a56138ca22722487eebacfd1eb5321d612", + "sha256:81a10926e5473c5fc3da8abb04119a1f5811a236dc3a38d92015cb1e6ba4cb9e", + "sha256:85ca5fcc24f0b4aeedc1d02f93707bccc04733f21d41c88334c5482219b1ccb3", + "sha256:a260627a570559181a9ea5de61ac6297aa5af202f06fd7ab093ce74e7181e43e", + "sha256:aceb1db093b04db5cd390821464504111b8ec3e351eb85afd1433490163d60cd", + "sha256:b685154e22e4e9199fc95f298661deea28aaede5ae16ccc8cbb1045e716b3e04", + "sha256:d357423fa57a489e8c47b7c85dfb96698caba13d66e086b412298a1a0ea3b0ed", + "sha256:d4d5ddc13421ba3e2e082a6c2d74c2ddb3979c39b582dacd53dd5d9431237185", + "sha256:e49499be624dead83927e70c756970a0bc8240e9f769389cdf5714b0784ca6bf", + "sha256:e54396d70be04b34f31d2edf3362c1edd023246c82f1730bbf8768c28db5361b", + "sha256:f88566144752999351725ac623471661c9d1cd8caa0134ff98cceeea181789f4", + "sha256:f8a67616990062232ee4c3952f41c779afac41405806042a8126fe96e098419f", + "sha256:fe28657de3bfec596bbeef01cb219833ad9d38dd5393fc649f4b366840baefe6" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.7.1" + "version": "==1.9.0" }, "mypy-extensions": { "hashes": [ @@ -462,11 +357,11 @@ }, "packaging": { "hashes": [ - "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", - "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" + "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", + "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9" ], "markers": "python_version >= '3.7'", - "version": "==23.2" + "version": "==24.0" }, "pathspec": { "hashes": [ @@ -478,155 +373,113 @@ }, "platformdirs": { "hashes": [ - "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380", - "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420" + "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068", + "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768" ], "markers": "python_version >= '3.8'", - "version": "==4.1.0" + "version": "==4.2.0" }, "pluggy": { "hashes": [ - "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12", - "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7" + "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981", + "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be" ], "markers": "python_version >= '3.8'", - "version": "==1.3.0" - }, - "pycparser": { - "hashes": [ - "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", - "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206" - ], - "version": "==2.21" + "version": "==1.4.0" }, "pydantic": { "hashes": [ - "sha256:80c50fb8e3dcecfddae1adbcc00ec5822918490c99ab31f6cf6140ca1c1429f0", - "sha256:ff177ba64c6faf73d7afa2e8cad38fd456c0dbe01c9954e71038001cd15a6edd" + "sha256:b1704e0847db01817624a6b86766967f552dd9dbf3afba4004409f908dcc84e6", + "sha256:cc46fce86607580867bdc3361ad462bab9c222ef042d3da86f2fb333e1d916c5" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==2.5.2" + "markers": "python_version >= '3.8'", + "version": "==2.6.4" }, "pydantic-core": { "hashes": [ - "sha256:038c9f763e650712b899f983076ce783175397c848da04985658e7628cbe873b", - "sha256:074f3d86f081ce61414d2dc44901f4f83617329c6f3ab49d2bc6c96948b2c26b", - "sha256:079206491c435b60778cf2b0ee5fd645e61ffd6e70c47806c9ed51fc75af078d", - "sha256:09b0e985fbaf13e6b06a56d21694d12ebca6ce5414b9211edf6f17738d82b0f8", - "sha256:0f6116a558fd06d1b7c2902d1c4cf64a5bd49d67c3540e61eccca93f41418124", - "sha256:103ef8d5b58596a731b690112819501ba1db7a36f4ee99f7892c40da02c3e189", - "sha256:16e29bad40bcf97aac682a58861249ca9dcc57c3f6be22f506501833ddb8939c", - "sha256:206ed23aecd67c71daf5c02c3cd19c0501b01ef3cbf7782db9e4e051426b3d0d", - "sha256:2248485b0322c75aee7565d95ad0e16f1c67403a470d02f94da7344184be770f", - "sha256:27548e16c79702f1e03f5628589c6057c9ae17c95b4c449de3c66b589ead0520", - "sha256:2d0ae0d8670164e10accbeb31d5ad45adb71292032d0fdb9079912907f0085f4", - "sha256:3128e0bbc8c091ec4375a1828d6118bc20404883169ac95ffa8d983b293611e6", - "sha256:3387277f1bf659caf1724e1afe8ee7dbc9952a82d90f858ebb931880216ea955", - "sha256:34708cc82c330e303f4ce87758828ef6e457681b58ce0e921b6e97937dd1e2a3", - "sha256:35613015f0ba7e14c29ac6c2483a657ec740e5ac5758d993fdd5870b07a61d8b", - "sha256:3ad873900297bb36e4b6b3f7029d88ff9829ecdc15d5cf20161775ce12306f8a", - "sha256:40180930807ce806aa71eda5a5a5447abb6b6a3c0b4b3b1b1962651906484d68", - "sha256:439c9afe34638ace43a49bf72d201e0ffc1a800295bed8420c2a9ca8d5e3dbb3", - "sha256:45e95333b8418ded64745f14574aa9bfc212cb4fbeed7a687b0c6e53b5e188cd", - "sha256:4641e8ad4efb697f38a9b64ca0523b557c7931c5f84e0fd377a9a3b05121f0de", - "sha256:49b08aae5013640a3bfa25a8eebbd95638ec3f4b2eaf6ed82cf0c7047133f03b", - "sha256:4bc536201426451f06f044dfbf341c09f540b4ebdb9fd8d2c6164d733de5e634", - "sha256:4ce601907e99ea5b4adb807ded3570ea62186b17f88e271569144e8cca4409c7", - "sha256:4e40f2bd0d57dac3feb3a3aed50f17d83436c9e6b09b16af271b6230a2915459", - "sha256:4e47a76848f92529879ecfc417ff88a2806438f57be4a6a8bf2961e8f9ca9ec7", - "sha256:513b07e99c0a267b1d954243845d8a833758a6726a3b5d8948306e3fe14675e3", - "sha256:531f4b4252fac6ca476fbe0e6f60f16f5b65d3e6b583bc4d87645e4e5ddde331", - "sha256:57d52fa717ff445cb0a5ab5237db502e6be50809b43a596fb569630c665abddf", - "sha256:59986de5710ad9613ff61dd9b02bdd2f615f1a7052304b79cc8fa2eb4e336d2d", - "sha256:5baab5455c7a538ac7e8bf1feec4278a66436197592a9bed538160a2e7d11e36", - "sha256:5c7d5b5005f177764e96bd584d7bf28d6e26e96f2a541fdddb934c486e36fd59", - "sha256:60b7607753ba62cf0739177913b858140f11b8af72f22860c28eabb2f0a61937", - "sha256:615a0a4bff11c45eb3c1996ceed5bdaa2f7b432425253a7c2eed33bb86d80abc", - "sha256:61ea96a78378e3bd5a0be99b0e5ed00057b71f66115f5404d0dae4819f495093", - "sha256:652c1988019752138b974c28f43751528116bcceadad85f33a258869e641d753", - "sha256:6637560562134b0e17de333d18e69e312e0458ee4455bdad12c37100b7cad706", - "sha256:678265f7b14e138d9a541ddabbe033012a2953315739f8cfa6d754cc8063e8ca", - "sha256:699156034181e2ce106c89ddb4b6504c30db8caa86e0c30de47b3e0654543260", - "sha256:6b9ff467ffbab9110e80e8c8de3bcfce8e8b0fd5661ac44a09ae5901668ba997", - "sha256:6c327e9cd849b564b234da821236e6bcbe4f359a42ee05050dc79d8ed2a91588", - "sha256:6d30226dfc816dd0fdf120cae611dd2215117e4f9b124af8c60ab9093b6e8e71", - "sha256:6e227c40c02fd873c2a73a98c1280c10315cbebe26734c196ef4514776120aeb", - "sha256:6e4d090e73e0725b2904fdbdd8d73b8802ddd691ef9254577b708d413bf3006e", - "sha256:70f4b4851dbb500129681d04cc955be2a90b2248d69273a787dda120d5cf1f69", - "sha256:70f947628e074bb2526ba1b151cee10e4c3b9670af4dbb4d73bc8a89445916b5", - "sha256:774de879d212db5ce02dfbf5b0da9a0ea386aeba12b0b95674a4ce0593df3d07", - "sha256:77fa384d8e118b3077cccfcaf91bf83c31fe4dc850b5e6ee3dc14dc3d61bdba1", - "sha256:79e0a2cdbdc7af3f4aee3210b1172ab53d7ddb6a2d8c24119b5706e622b346d0", - "sha256:7e88f5696153dc516ba6e79f82cc4747e87027205f0e02390c21f7cb3bd8abfd", - "sha256:7f8210297b04e53bc3da35db08b7302a6a1f4889c79173af69b72ec9754796b8", - "sha256:81982d78a45d1e5396819bbb4ece1fadfe5f079335dd28c4ab3427cd95389944", - "sha256:823fcc638f67035137a5cd3f1584a4542d35a951c3cc68c6ead1df7dac825c26", - "sha256:853a2295c00f1d4429db4c0fb9475958543ee80cfd310814b5c0ef502de24dda", - "sha256:88e74ab0cdd84ad0614e2750f903bb0d610cc8af2cc17f72c28163acfcf372a4", - "sha256:8aa1768c151cf562a9992462239dfc356b3d1037cc5a3ac829bb7f3bda7cc1f9", - "sha256:8c8a8812fe6f43a3a5b054af6ac2d7b8605c7bcab2804a8a7d68b53f3cd86e00", - "sha256:95b15e855ae44f0c6341ceb74df61b606e11f1087e87dcb7482377374aac6abe", - "sha256:96581cfefa9123accc465a5fd0cc833ac4d75d55cc30b633b402e00e7ced00a6", - "sha256:9bd18fee0923ca10f9a3ff67d4851c9d3e22b7bc63d1eddc12f439f436f2aada", - "sha256:a33324437018bf6ba1bb0f921788788641439e0ed654b233285b9c69704c27b4", - "sha256:a6a16f4a527aae4f49c875da3cdc9508ac7eef26e7977952608610104244e1b7", - "sha256:a717aef6971208f0851a2420b075338e33083111d92041157bbe0e2713b37325", - "sha256:a71891847f0a73b1b9eb86d089baee301477abef45f7eaf303495cd1473613e4", - "sha256:aae7ea3a1c5bb40c93cad361b3e869b180ac174656120c42b9fadebf685d121b", - "sha256:ab1cdb0f14dc161ebc268c09db04d2c9e6f70027f3b42446fa11c153521c0e88", - "sha256:ab4ea451082e684198636565224bbb179575efc1658c48281b2c866bfd4ddf04", - "sha256:abf058be9517dc877227ec3223f0300034bd0e9f53aebd63cf4456c8cb1e0863", - "sha256:af36f36538418f3806048f3b242a1777e2540ff9efaa667c27da63d2749dbce0", - "sha256:b53e9ad053cd064f7e473a5f29b37fc4cc9dc6d35f341e6afc0155ea257fc911", - "sha256:b7851992faf25eac90bfcb7bfd19e1f5ffa00afd57daec8a0042e63c74a4551b", - "sha256:b9b759b77f5337b4ea024f03abc6464c9f35d9718de01cfe6bae9f2e139c397e", - "sha256:ba39688799094c75ea8a16a6b544eb57b5b0f3328697084f3f2790892510d144", - "sha256:ba6b6b3846cfc10fdb4c971980a954e49d447cd215ed5a77ec8190bc93dd7bc5", - "sha256:bb4c2eda937a5e74c38a41b33d8c77220380a388d689bcdb9b187cf6224c9720", - "sha256:c0b97ec434041827935044bbbe52b03d6018c2897349670ff8fe11ed24d1d4ab", - "sha256:c1452a1acdf914d194159439eb21e56b89aa903f2e1c65c60b9d874f9b950e5d", - "sha256:c2027d05c8aebe61d898d4cffd774840a9cb82ed356ba47a90d99ad768f39789", - "sha256:c2adbe22ab4babbca99c75c5d07aaf74f43c3195384ec07ccbd2f9e3bddaecec", - "sha256:c2d97e906b4ff36eb464d52a3bc7d720bd6261f64bc4bcdbcd2c557c02081ed2", - "sha256:c339dabd8ee15f8259ee0f202679b6324926e5bc9e9a40bf981ce77c038553db", - "sha256:c6eae413494a1c3f89055da7a5515f32e05ebc1a234c27674a6956755fb2236f", - "sha256:c949f04ecad823f81b1ba94e7d189d9dfb81edbb94ed3f8acfce41e682e48cef", - "sha256:c97bee68898f3f4344eb02fec316db93d9700fb1e6a5b760ffa20d71d9a46ce3", - "sha256:ca61d858e4107ce5e1330a74724fe757fc7135190eb5ce5c9d0191729f033209", - "sha256:cb4679d4c2b089e5ef89756bc73e1926745e995d76e11925e3e96a76d5fa51fc", - "sha256:cb774298da62aea5c80a89bd58c40205ab4c2abf4834453b5de207d59d2e1651", - "sha256:ccd4d5702bb90b84df13bd491be8d900b92016c5a455b7e14630ad7449eb03f8", - "sha256:cf9d3fe53b1ee360e2421be95e62ca9b3296bf3f2fb2d3b83ca49ad3f925835e", - "sha256:d2ae91f50ccc5810b2f1b6b858257c9ad2e08da70bf890dee02de1775a387c66", - "sha256:d37f8ec982ead9ba0a22a996129594938138a1503237b87318392a48882d50b7", - "sha256:d81e6987b27bc7d101c8597e1cd2bcaa2fee5e8e0f356735c7ed34368c471550", - "sha256:dcf4e6d85614f7a4956c2de5a56531f44efb973d2fe4a444d7251df5d5c4dcfd", - "sha256:de790a3b5aa2124b8b78ae5faa033937a72da8efe74b9231698b5a1dd9be3405", - "sha256:e47e9a08bcc04d20975b6434cc50bf82665fbc751bcce739d04a3120428f3e27", - "sha256:e60f112ac88db9261ad3a52032ea46388378034f3279c643499edb982536a093", - "sha256:e87fc540c6cac7f29ede02e0f989d4233f88ad439c5cdee56f693cc9c1c78077", - "sha256:eac5c82fc632c599f4639a5886f96867ffced74458c7db61bc9a66ccb8ee3113", - "sha256:ebb4e035e28f49b6f1a7032920bb9a0c064aedbbabe52c543343d39341a5b2a3", - "sha256:ec1e72d6412f7126eb7b2e3bfca42b15e6e389e1bc88ea0069d0cc1742f477c6", - "sha256:ef98ca7d5995a82f43ec0ab39c4caf6a9b994cb0b53648ff61716370eadc43cf", - "sha256:f0cbc7fff06a90bbd875cc201f94ef0ee3929dfbd5c55a06674b60857b8b85ed", - "sha256:f4791cf0f8c3104ac668797d8c514afb3431bc3305f5638add0ba1a5a37e0d88", - "sha256:f5e412d717366e0677ef767eac93566582518fe8be923361a5c204c1a62eaafe", - "sha256:fb2ed8b3fe4bf4506d6dab3b93b83bbc22237e230cba03866d561c3577517d18", - "sha256:fe0a5a1025eb797752136ac8b4fa21aa891e3d74fd340f864ff982d649691867" - ], - "markers": "python_version >= '3.7'", - "version": "==2.14.5" - }, - "pygithub": { - "hashes": [ - "sha256:4b528d5d6f35e991ea5fd3f942f58748f24938805cb7fcf24486546637917337", - "sha256:ecf12c2809c44147bce63b047b3d2e9dac8a41b63e90fcb263c703f64936b97c" + "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a", + "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed", + "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979", + "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff", + "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5", + "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45", + "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340", + "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad", + "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23", + "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6", + "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7", + "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241", + "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda", + "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187", + "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba", + "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c", + "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2", + "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c", + "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132", + "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf", + "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972", + "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db", + "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade", + "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4", + "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8", + "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f", + "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9", + "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48", + "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec", + "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d", + "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9", + "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb", + "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4", + "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89", + "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c", + "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9", + "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da", + "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac", + "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b", + "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf", + "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e", + "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137", + "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1", + "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b", + "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8", + "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e", + "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053", + "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01", + "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe", + "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd", + "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805", + "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183", + "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8", + "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99", + "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820", + "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074", + "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256", + "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8", + "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975", + "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad", + "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e", + "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca", + "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df", + "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b", + "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a", + "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a", + "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721", + "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a", + "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f", + "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2", + "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97", + "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6", + "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed", + "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc", + "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1", + "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe", + "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120", + "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f", + "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a" ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==2.1.1" + "markers": "python_version >= '3.8'", + "version": "==2.16.3" }, "pygments": { "hashes": [ @@ -636,41 +489,6 @@ "markers": "python_version >= '3.7'", "version": "==2.17.2" }, - "pyjwt": { - "extras": [ - "crypto" - ], - "hashes": [ - "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de", - "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320" - ], - "markers": "python_version >= '3.7'", - "version": "==2.8.0" - }, - "pynacl": { - "hashes": [ - "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858", - "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d", - "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93", - "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1", - "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92", - "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff", - "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba", - "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394", - "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b", - "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543" - ], - "markers": "python_version >= '3.6'", - "version": "==1.5.0" - }, - "pyreadline3": { - "hashes": [ - "sha256:6f3d1f7b8a31ba32b73917cefc1f28cc660562f39aea8646d30bd6eff21f7bae", - "sha256:b0efb6516fd4fb07b45949053826a62fa4cb353db5be2bbb4a7aa1fdd1e345fb" - ], - "index": "pypi", - "version": "==3.4.1" - }, "pysocks": { "hashes": [ "sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299", @@ -681,12 +499,12 @@ }, "pytest": { "hashes": [ - "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac", - "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5" + "sha256:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7", + "sha256:ac978141a75948948817d360297b7aae0fcb9d6ff6bc9ec6d514b85d5a65c044" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==7.4.3" + "markers": "python_version >= '3.8'", + "version": "==8.1.1" }, "pytest-html": { "hashes": [ @@ -699,37 +517,20 @@ }, "pytest-metadata": { "hashes": [ - "sha256:769a9c65d2884bd583bc626b0ace77ad15dbe02dd91a9106d47fd46d9c2569ca", - "sha256:a17b1e40080401dc23177599208c52228df463db191c1a573ccdffacd885e190" - ], - "markers": "python_version >= '3.7'", - "version": "==3.0.0" - }, - "pytest-xdist": { - "hashes": [ - "sha256:cbb36f3d67e0c478baa57fa4edc8843887e0f6cfc42d677530a36d7472b32d8a", - "sha256:d075629c7e00b611df89f490a5063944bee7a4362a5ff11c7cc7824a03dfce24" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==3.5.0" - }, - "python-dateutil": { - "hashes": [ - "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", - "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" + "sha256:c8e0844db684ee1c798cfa38908d20d67d0463ecb6137c72e91f418558dd5f4b", + "sha256:d2a29b0355fbc03f168aa96d41ff88b1a3b44a3b02acbe491801c98a048017c8" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.8.2" + "markers": "python_version >= '3.8'", + "version": "==3.1.1" }, "python-dotenv": { "hashes": [ - "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba", - "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a" + "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", + "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.0.0" + "version": "==1.0.1" }, "requests": { "hashes": [ @@ -742,61 +543,53 @@ }, "rich": { "hashes": [ - "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa", - "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235" + "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222", + "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432" ], "index": "pypi", "markers": "python_full_version >= '3.7.0'", - "version": "==13.7.0" + "version": "==13.7.1" }, "ruff": { "hashes": [ - "sha256:03910e81df0d8db0e30050725a5802441c2022ea3ae4fe0609b76081731accbc", - "sha256:05991ee20d4ac4bb78385360c684e4b417edd971030ab12a4fbd075ff535050e", - "sha256:137852105586dcbf80c1717facb6781555c4e99f520c9c827bd414fac67ddfb6", - "sha256:1610e14750826dfc207ccbcdd7331b6bd285607d4181df9c1c6ae26646d6848a", - "sha256:1b09f29b16c6ead5ea6b097ef2764b42372aebe363722f1605ecbcd2b9207184", - "sha256:1cf5f701062e294f2167e66d11b092bba7af6a057668ed618a9253e1e90cfd76", - "sha256:3a0cd909d25f227ac5c36d4e7e681577275fb74ba3b11d288aff7ec47e3ae745", - "sha256:4558b3e178145491e9bc3b2ee3c4b42f19d19384eaa5c59d10acf6e8f8b57e33", - "sha256:491262006e92f825b145cd1e52948073c56560243b55fb3b4ecb142f6f0e9543", - "sha256:5c549ed437680b6105a1299d2cd30e4964211606eeb48a0ff7a93ef70b902248", - "sha256:683aa5bdda5a48cb8266fcde8eea2a6af4e5700a392c56ea5fb5f0d4bfdc0240", - "sha256:87455a0c1f739b3c069e2f4c43b66479a54dea0276dd5d4d67b091265f6fd1dc", - "sha256:88b8cdf6abf98130991cbc9f6438f35f6e8d41a02622cc5ee130a02a0ed28703", - "sha256:bd98138a98d48a1c36c394fd6b84cd943ac92a08278aa8ac8c0fdefcf7138f35", - "sha256:e8fd1c62a47aa88a02707b5dd20c5ff20d035d634aa74826b42a1da77861b5ff", - "sha256:ea284789861b8b5ca9d5443591a92a397ac183d4351882ab52f6296b4fdd5462", - "sha256:fd89b45d374935829134a082617954120d7a1470a9f0ec0e7f3ead983edc48cc" + "sha256:3f3860057590e810c7ffea75669bdc6927bfd91e29b4baa9258fd48b540a4365", + "sha256:519cf6a0ebed244dce1dc8aecd3dc99add7a2ee15bb68cf19588bb5bf58e0488", + "sha256:60c870a7d46efcbc8385d27ec07fe534ac32f3b251e4fc44b3cbfd9e09609ef4", + "sha256:64abeed785dad51801b423fa51840b1764b35d6c461ea8caef9cf9e5e5ab34d9", + "sha256:6810563cc08ad0096b57c717bd78aeac888a1bfd38654d9113cb3dc4d3f74232", + "sha256:6fc14fa742e1d8f24910e1fff0bd5e26d395b0e0e04cc1b15c7c5e5fe5b4af91", + "sha256:986f2377f7cf12efac1f515fc1a5b753c000ed1e0a6de96747cdf2da20a1b369", + "sha256:98e98300056445ba2cc27d0b325fd044dc17fcc38e4e4d2c7711585bd0a958ed", + "sha256:af27ac187c0a331e8ef91d84bf1c3c6a5dea97e912a7560ac0cef25c526a4102", + "sha256:bb0acfb921030d00070539c038cd24bb1df73a2981e9f55942514af8b17be94e", + "sha256:c4fd98e85869603e65f554fdc5cddf0712e352fe6e61d29d5a6fe087ec82b76c", + "sha256:cf133dd744f2470b347f602452a88e70dadfbe0fcfb5fd46e093d55da65f82f7", + "sha256:cf187a7e7098233d0d0c71175375c5162f880126c4c716fa28a8ac418dcf3378", + "sha256:d3ee7880f653cc03749a3bfea720cf2a192e4f884925b0cf7eecce82f0ce5854", + "sha256:de0d5069b165e5a32b3c6ffbb81c350b1e3d3483347196ffdf86dc0ef9e37dd6", + "sha256:df52972138318bc7546d92348a1ee58449bc3f9eaf0db278906eb511889c4b50", + "sha256:f0f4484c6541a99862b693e13a151435a279b271cff20e37101116a21e2a1ad1" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==0.1.6" + "version": "==0.3.4" }, "selenium": { "hashes": [ - "sha256:22eab5a1724c73d51b240a69ca702997b717eee4ba1f6065bf5d6b44dba01d48", - "sha256:9e82cd1ac647fb73cf0d4a6e280284102aaa3c9d94f0fa6e6cc4b5db6a30afbf" + "sha256:5b4f49240d61e687a73f7968ae2517d403882aae3550eae2a229c745e619f1d9", + "sha256:d9dfd6d0b021d71d0a48b865fe7746490ba82b81e9c87b212360006629eb1853" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.15.2" - }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.16.0" + "version": "==4.19.0" }, "sniffio": { "hashes": [ - "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101", - "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384" + "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", + "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" ], "markers": "python_version >= '3.7'", - "version": "==1.3.0" + "version": "==1.3.1" }, "sortedcontainers": { "hashes": [ @@ -807,20 +600,20 @@ }, "syrupy": { "hashes": [ - "sha256:231b1f5d00f1f85048ba81676c79448076189c4aef4d33f21ae32f3b4c565a54", - "sha256:747aae1bcf3cb3249e33b1e6d81097874d23615982d5686ebe637875b0775a1b" + "sha256:203e52f9cb9fa749cf683f29bd68f02c16c3bc7e7e5fe8f2fc59bdfe488ce133", + "sha256:37a835c9ce7857eeef86d62145885e10b3cb9615bc6abeb4ce404b3f18e1bb36" ], "index": "pypi", "markers": "python_version < '4' and python_full_version >= '3.8.1'", - "version": "==4.6.0" + "version": "==4.6.1" }, "trio": { "hashes": [ - "sha256:5a0b566fa5d50cf231cfd6b08f3b03aa4179ff004b8f3144059587039e2b26d3", - "sha256:da1d35b9a2b17eb32cae2e763b16551f9aa6703634735024e32f325c9285069e" + "sha256:9b41f5993ad2c0e5f62d0acca320ec657fdb6b2a2c22b8c7aed6caf154475c4e", + "sha256:e6458efe29cc543e557a91e614e2b51710eba2961669329ce9c862d50c6e8e81" ], "markers": "python_version >= '3.8'", - "version": "==0.23.2" + "version": "==0.25.0" }, "trio-websocket": { "hashes": [ @@ -832,115 +625,31 @@ }, "types-requests": { "hashes": [ - "sha256:b32b9a86beffa876c0c3ac99a4cd3b8b51e973fb8e3bd4e0a6bb32c7efad80fc", - "sha256:dc5852a76f1eaf60eafa81a2e50aefa3d1f015c34cf0cba130930866b1b22a92" + "sha256:47872893d65a38e282ee9f277a4ee50d1b28bd592040df7d1fdaffdf3779937d", + "sha256:b1c1b66abfb7fa79aae09097a811c4aa97130eb8831c60e47aee4ca344731ca5" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==2.31.0.10" + "markers": "python_version >= '3.8'", + "version": "==2.31.0.20240311" }, "typing-extensions": { "hashes": [ - "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", - "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", + "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb" ], "markers": "python_version >= '3.8'", - "version": "==4.9.0" + "version": "==4.10.0" }, "urllib3": { "extras": [ "socks" ], "hashes": [ - "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3", - "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54" - ], - "markers": "python_version >= '3.8'", - "version": "==2.1.0" - }, - "websocket-client": { - "hashes": [ - "sha256:10e511ea3a8c744631d3bd77e61eb17ed09304c413ad42cf6ddfa4c7787e8fe6", - "sha256:f4c3d22fec12a2461427a29957ff07d35098ee2d976d3ba244e688b8b4057588" + "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", + "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19" ], "markers": "python_version >= '3.8'", - "version": "==1.7.0" - }, - "wrapt": { - "hashes": [ - "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc", - "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81", - "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09", - "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e", - "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca", - "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0", - "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb", - "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487", - "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40", - "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c", - "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060", - "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202", - "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41", - "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9", - "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b", - "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664", - "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d", - "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362", - "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00", - "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc", - "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1", - "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267", - "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956", - "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966", - "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1", - "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228", - "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72", - "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d", - "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292", - "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0", - "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0", - "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36", - "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c", - "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5", - "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f", - "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73", - "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b", - "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2", - "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593", - "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39", - "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389", - "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf", - "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf", - "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89", - "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c", - "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c", - "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f", - "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440", - "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465", - "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136", - "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b", - "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8", - "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3", - "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8", - "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6", - "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e", - "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f", - "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c", - "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e", - "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8", - "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2", - "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020", - "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35", - "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d", - "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3", - "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537", - "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809", - "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d", - "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a", - "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4" - ], - "markers": "python_version >= '3.6'", - "version": "==1.16.0" + "version": "==2.2.1" }, "wsproto": { "hashes": [ @@ -952,11 +661,11 @@ }, "zipp": { "hashes": [ - "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31", - "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0" + "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b", + "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715" ], "markers": "python_version >= '3.8'", - "version": "==3.17.0" + "version": "==3.18.1" } }, "develop": {} diff --git a/app-testing/README.md b/app-testing/README.md index c3be77d34fa..ec2e149ec18 100644 --- a/app-testing/README.md +++ b/app-testing/README.md @@ -68,35 +68,35 @@ pipenv run python -i locators.py - Only have 1 robot connected at once. - Build locators like you have more than 1 to future proof. -## Analysis Test +### Analyses Snapshot Test -The analysis test `pipenv run pytest -k test_analyses` is driven by the comma delimited string variable `APP_ANALYSIS_TEST_PROTOCOLS` in `.env` -This allows us to run one or many. +> The primary test in this module. -### Adding protocols to the analysis test +The analyses snapshot test runs protocol analysis using `TARGET` branch or tag then compares them against snapshots found on `TEST_SOURCE` branch or tag. -1. add the protocol file named according to the naming convention in the files/protocols appropriate folder -1. add the protocol stem to `protocol_files.py` -1. add the protocol data as a property to `protocols.py` -1. run `make print-protocols` +#### Protocol Files Location -### Analyses Snapshot Test +The set of protocols to analyze is defined inside of `app-testing/.env` file, under the `APP_ANALYSIS_TEST_PROTOCOLS` and `APP_ANALYSIS_TEST_PROTOCOLS_WITH_OVERRIDES` variables. -The analyses snapshot test runs protocol analysis using `TARGET` branch or tag then compares them against snapshots found on `TEST_SOURCE` branch or tag. +#### Protocol Files with Overrides -#### Protocol Files Location +Sometimes we want to have a bunch of protocols that are just slightly different from each other. This is especially helpful with negative test cases. We can have a protocol that depending on the value of a variable does different things. You may then override the variable to test different scenarios. -The set of protocols to analyze is defined inside of `app-testing/.env` file, under the `APP_ANALYSIS_TEST_PROTOCOLS` variable. These protocols must exist inside of `app-testing/files/protocols` folder. +The best way to learn this is by example. Look at: -- Protocol Designer protocols go in the `json` folder -- Python protocols go in the `python` folder. +- `app-testing/files/protocolsFlex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP.py` +- `app-testing/automation/data/protocols_with_overrides.py` +- `make generate-protocols` +- see the protocols generated in `app-testing/files/generated_protocols/` #### Analysis Snapshots Location -Analysis snapshots are located inside of `app-testing/tests/__snapshots__/analyses_snapshot_test` folder. +Analysis snapshots are located inside of `app-testing/tests/__snapshots__/analyses_snapshot_test` folder. These are generated. If you want to update them, see below. #### Running Analysis Snapshot Tests Locally +> Note: Passing `TARGET` can be done as below or in the `.env` file. + To run analysis snapshot tests locally, you must first build the Docker image by running the following command: ```bash @@ -135,6 +135,6 @@ Given the scenario that you want to see if the latest version of `chore_release- - If you want to compare against the previous release branch, then TEST_SOURCE is chore_release-v7.1.0. - If you want to compare your in-progress release branch against the previous release branch, then TEST_SOURCE is ``. -run the Workflow Dispatch job +##### Run the Workflow Dispatch job - `gh workflow run 'Analyses Snapshot Test' --ref chore_release-v7.2.0 -f TARGET=chore_release-v7.2.0 -f TEST_SOURCE=chore_release-v7.1.0` diff --git a/app-testing/automation/data/protocol.py b/app-testing/automation/data/protocol.py index 8aa133e2658..71c33ed0ce1 100644 --- a/app-testing/automation/data/protocol.py +++ b/app-testing/automation/data/protocol.py @@ -1,4 +1,5 @@ """Model of a protocol for testing.""" + import hashlib import os from pathlib import Path @@ -6,17 +7,18 @@ from pydantic import BaseModel, Field -from automation.data.protocol_files import names from automation.resources.robot_data import module_types +GENERATED_PROTOCOLS_FOLDER = "generated_protocols" +OVERRIDE_MONIKER = "_Override_" + class Protocol(BaseModel): """Model to describe a protocol used in a test.""" - file_name: names = Field(description="file name not including extension") + file_stem: str = Field(description="file name not including extension") file_extension: Literal["json", "py"] = Field(description="file extension of the protocol") - protocol_name: str = Field(description="the protocol name which will appear in the protocol name field in the app") - robot: Literal["OT-2", "Flex"] = Field(description="the robot type which will appear in the robot field in the app") + robot: Literal["OT2", "Flex"] = Field(description="the robot type which will appear in the robot field in the app") app_error: bool = Field(description="will analysis with the app raise an error") robot_error: bool = Field(description="will analysis with the robot raise an error") app_analysis_error: Optional[str] = Field(description="the exact error shown in the app popout", default=None) @@ -26,17 +28,27 @@ class Protocol(BaseModel): modules: Optional[list[module_types]] = Field(description="list of modules that will show in the app", default=None) description: Optional[str] = Field(description="Details about this protocol", default=None) expected_test_failure: bool = Field(description="Is this test expected to fail", default=False) - expected_test_reason: Optional[str] = Field(description="Reason test is failing", default=False) + expected_test_reason: Optional[str] = Field(description="Reason test is failing", default=None) + override_variable_name: Optional[str] = Field(description="The variable name to override", default=None) + override_value: Optional[str] = Field(description="The value of the override", default=None) + from_override: bool = Field(description="Is this protocol generated from an override", default=False) @property def file_path(self) -> Path: """Path of the file.""" + if self.from_override: + return Path( + Path(__file__).resolve().parent.parent.parent, + os.getenv("FILES_FOLDER", "files"), + "protocols", + GENERATED_PROTOCOLS_FOLDER, + f"{self.file_stem}.{self.file_extension}", + ) return Path( Path(__file__).resolve().parent.parent.parent, os.getenv("FILES_FOLDER", "files"), "protocols", - f"{self.file_extension}", - f"{self.file_name}.{self.file_extension}", + f"{self.file_stem}.{self.file_extension}", ) @property @@ -58,6 +70,6 @@ def labware_paths(self) -> list[Path]: def short_sha(self) -> str: """Short sha of the file.""" # Hash the string using SHA-1 - hash_object = hashlib.sha1(self.file_name.encode()) + hash_object = hashlib.sha1(self.file_stem.encode()) # Convert to hexadecimal and truncate return hash_object.hexdigest()[:10] diff --git a/app-testing/automation/data/protocol_files.py b/app-testing/automation/data/protocol_files.py deleted file mode 100644 index f2dbccfb519..00000000000 --- a/app-testing/automation/data/protocol_files.py +++ /dev/null @@ -1,88 +0,0 @@ -"""Define the possible names of protocol files to use in testing.""" -from typing import Literal - -names = Literal[ - "OT2_P300SLeft_MM1_MM_TM_2_3_Mix", - "OT2_P300SLeft_MM1_MM_2_2_EngageMagHeightFromBase", - "OT2_P300SLeft_MM_TM_TM_5_2_6_MOAMTemps", - "OT2_P300SG1_None_5_2_6_Gen1PipetteSimple", - "OT2_P300S_Twinning_Error", - "OT2_P300S_Thermocycler_Moam_Error", - "OT2_P300S_None_2_16_verifyNoFloatingPointErrorInPipetting", - "OT2_P300MLeft_MM_TM_2_4_Zymo", - "OT2_P300M_P300S_HS_6_1_HS_NormalUseWithTransfer", - "OT2_P300M_P20S_TC_MM_TM_2_13_Smoke620Release", - "OT2_P300M_P20S_TC_HS_TM_2_17_SmokeTestV3", - "OT2_P300M_P20S_TC_HS_TM_2_17_dispense_changes", - "OT2_P300M_P20S_TC_HS_TM_2_16_SmokeTestV3", - "OT2_P300M_P20S_TC_HS_TM_2_16_dispense_changes", - "OT2_P300M_P20S_TC_HS_TM_2_16_aspirateDispenseMix0Volume", - "OT2_P300M_P20S_TC_HS_TM_2_15_SmokeTestV3", - "OT2_P300M_P20S_TC_HS_TM_2_15_dispense_changes", - "OT2_P300M_P20S_TC_HS_TM_2_14_SmokeTestV3", - "OT2_P300M_P20S_TC_HS_TM_2_13_SmokeTestV3", - "OT2_P300M_P20S_None_2_12_FailOnRun", - "OT2_P300M_P20S_NoMod_6_1_MixTransferManyLiquids", - "OT2_P300M_P20S_MM_TM_TC1_5_2_6_PD40Error", - "OT2_P300M_P20S_MM_TM_TC1_5_2_6_PD40", - "OT2_P300M_P20S_MM_HS_TD_TC_6_1_AllMods_Error", - "OT2_P300M_P20S_HS_6_1_Smoke620release", - "OT2_P300M_P20S_2_16_aspirateDispenseMix0Volume", - "OT2_P20SRight_None_6_1_SimpleTransferError", - "OT2_P20S_P300M_NoMods_6_1_TransferReTransferLiquid", - "OT2_P20S_P300M_HS_6_1_HS_WithCollision_Error", - "OT2_P20S_None_2_7_Walkthrough", - "OT2_P10S_P300M_TC1_TM_MM_2_11_Swift", - "OT2_P1000SLeft_None_6_1_SimpleTransfer", - "OT2_None_None_TC_2_17_VerifyThermocyclerLoadedSlots", - "OT2_None_None_TC_2_16_VerifyThermocyclerLoadedSlots", - "OT2_None_None_TC_2_15_VerifyThermocyclerLoadedSlots", - "OT2_None_None_TC_2_14_VerifyThermocyclerLoadedSlots", - "OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin2", - "OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin1", - "OT2_None_None_2_16_verifyDoesNotDeadlock", - "OT2_None_None_2_13_PythonSyntaxError", - "OT2_None_None_2_12_Python310SyntaxRobotAnalysisOnlyError", - "Flex_P50MLeft_P1000MRight_None_2_15_ABRKAPALibraryQuantLongv2", - "Flex_P300Gen2_None_2_16_AnalysisError_OT2PipetteInFlexProtocol", - "Flex_P1000SRight_None_2_15_ABR_Simple_Normalize_Long_Right", - "Flex_P1000MLeft_P50MRight_HS_TM_MM_TC_2_15_ABR4_Illumina_DNA_Prep_24x", - "Flex_P1000MLeft_P50MRight_HS_MM_TC_TM_2_15_ABR3_Illumina_DNA_Enrichment", - "Flex_P1000MLeft_P50MRight_HS_MM_TC_TM_2_15_ABR3_Illumina_DNA_Enrichment_v4", - "Flex_P1000_96_TM_2_16_AnalysisError_ModuleAndWasteChuteConflict", - "Flex_P1000_96_TC_2_16_PartialTipPickupSingle", - "Flex_P1000_96_TC_2_16_PartialTipPickupColumn", - "Flex_P1000_96_TC_2_16_AnalysisError_PartialTipPickupTryToReturnTip", - "Flex_P1000_96_TC_2_16_AnalysisError_PartialTipPickupThermocyclerLidConflict", - "Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLidClips", - "Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLid", - "Flex_P1000_96_None_2_16_AnalysisError_TrashBinInStagingAreaCol3", - "Flex_P1000_96_None_2_15_ABR5_6_IDT_xGen_EZ_96x_Head_PART_I_III_ABR", - "Flex_P1000_96_HS_TM_TC_MM_2_15_ABR5_6_Illumina_DNA_Prep_96x_Head_PART_III", - "Flex_P1000_96_HS_TM_MM_2_15_MagMaxRNACells96Ch", - "Flex_P1000_96_HS_TM_MM_2_15_ABR5_6_HDQ_Bacteria_ParkTips_96_channel", - "Flex_P1000_96_Gripper_TC_TM_HS_prepareForMountMovement", - "Flex_P1000_96_Gripper_TC_TM_HS_AnalysisError_GripperCollisionWithTips", - "Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_Smoke", - "Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1", - "Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoModulesNoFixtures", - "Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoModules", - "Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoFixtures", - "Flex_P1000_96_GRIPPER_2_16_AnalysisError_DropLabwareIntoTrashBin", - "Flex_P1000_96_2_16_AnalysisError_DropTipsWithNoTrash", - "Flex_P100_96_HS_TM_2_15_Quick_Zymo_RNA_Bacteria", - "Flex_None_None_TM_2_16_AnalysisError_ModuleInStagingAreaCol4", - "Flex_None_None_TM_2_16_AnalysisError_ModuleInStagingAreaCol3", - "Flex_None_None_TM_2_16_AnalysisError_ModuleInCol2", - "Flex_None_None_TC_2_17_verifyThermocyclerLoadedSlots", - "Flex_None_None_TC_2_16_verifyThermocyclerLoadedSlots", - "Flex_None_None_TC_2_16_AnalysisError_TrashBinAndThermocyclerConflict", - "Flex_None_None_TC_2_15_verifyThermocyclerLoadedSlots", - "Flex_None_None_TC_2_14_verifyThermocyclerLoadedSlots", - "Flex_None_None_MM_2_16_AnalysisError_MagneticModuleInFlexProtocol", - "Flex_None_None_2_16_AnalysisError_TrashBinInStagingAreaCol4", - "Flex_None_None_2_16_AnalysisError_TrashBinInStagingAreaCol3", - "Flex_None_None_2_16_AnalysisError_TrashBinInCol2", - "Flex_None_None_2_16_AnalysisError_AccessToFixedTrashProp", - "Flex_P1000_96_Gripper_2_16_TriggerPrepareForMountMovement", -] diff --git a/app-testing/automation/data/protocol_registry.py b/app-testing/automation/data/protocol_registry.py new file mode 100644 index 00000000000..d22bd1620cc --- /dev/null +++ b/app-testing/automation/data/protocol_registry.py @@ -0,0 +1,84 @@ +import os +from pathlib import Path +from typing import Optional + +from rich.console import Console +from rich.panel import Panel + +from automation.data.protocol import Protocol +from automation.data.protocol_with_overrides import ProtocolWithOverrides +from automation.data.protocols import Protocols +from automation.data.protocols_with_overrides import ProtocolsWithOverrides + + +class ProtocolRegistry: + def __init__(self) -> None: + self.protocols: Protocols = Protocols() + self.protocols_with_overrides: ProtocolsWithOverrides = ProtocolsWithOverrides() + self.protocols_to_test: Optional[list[Protocol]] = self._what_protocols() + + def _what_protocols(self) -> Optional[list[Protocol]]: + protocol_names: Optional[str] = os.environ.get("APP_ANALYSIS_TEST_PROTOCOLS") + override_protocol_names: Optional[str] = os.environ.get("APP_ANALYSIS_TEST_PROTOCOLS_WITH_OVERRIDES") + protocols_to_test: list[Protocol] = [] + if protocol_names: + for protocol_name in [x.strip() for x in protocol_names.split(",")]: + protocol: Protocol = getattr(self.protocols, protocol_name) # raises + protocols_to_test.append(protocol) + if override_protocol_names: + for protocol_with_overrides__name in [x.strip() for x in override_protocol_names.split(",")]: + protocol_with_overrides: ProtocolWithOverrides = getattr( + self.protocols_with_overrides, protocol_with_overrides__name + ) # raises + if protocol_with_overrides.protocols is not None: + protocols_to_test.extend(protocol_with_overrides.protocols) + if protocols_to_test == []: + return None + return protocols_to_test + + def all_defined_protocols(self) -> list[Protocol]: + return [getattr(self.protocols, prop) for prop in dir(self.protocols) if "__" not in prop] + + def all_defined_protocols_with_overrides(self) -> list[ProtocolWithOverrides]: + return [getattr(self.protocols_with_overrides, prop) for prop in dir(self.protocols_with_overrides) if "__" not in prop] + + +def all_stems() -> set[str]: + dir_path = Path(Path(__file__).resolve().parent.parent.parent, os.getenv("FILES_FOLDER", "files"), "protocols") + file_stems = {file.stem for file in dir_path.glob("*.py")} + return file_stems + + +def main() -> None: + console = Console() + protocol_registry = ProtocolRegistry() + console.print("protocols for APP_ANALYSIS_TEST_PROTOCOLS") + console.print(Panel("Formatted for .env")) + regular_stems = sorted([p.file_stem for p in protocol_registry.all_defined_protocols()]) + console.print('APP_ANALYSIS_TEST_PROTOCOLS="') + console.print(",\n".join(regular_stems)) + console.print('"') + override_stems = sorted([p.file_stem for p in protocol_registry.all_defined_protocols_with_overrides()]) + console.print('APP_ANALYSIS_TEST_PROTOCOLS_WITH_OVERRIDES="') + console.print(",\n".join(override_stems)) + console.print('"') + + all_files = all_stems() + filtered_stems = {stem for stem in all_files if "overrides" not in stem.lower()} + found_override_stems = {stem for stem in all_files if "overrides" in stem.lower()} + # Finding and displaying differences + differences = filtered_stems - set(regular_stems) + if differences: + console.print(f"Stems in actual files not in mapping: {differences}") + else: + console.print("No differences between files and mapping.") + + differences = found_override_stems - set(override_stems) + if differences: + console.print(f"Override Stems in actual files not in mapping: {differences}") + else: + console.print("No differences between actual override protocols and the mapping.") + + +if __name__ == "__main__": + main() diff --git a/app-testing/automation/data/protocol_with_overrides.py b/app-testing/automation/data/protocol_with_overrides.py new file mode 100644 index 00000000000..f1410ac5f32 --- /dev/null +++ b/app-testing/automation/data/protocol_with_overrides.py @@ -0,0 +1,56 @@ +"""Model of a protocol for testing.""" + +from pathlib import Path +from typing import Any, Optional + +from pydantic import Field + +from automation.data.protocol import GENERATED_PROTOCOLS_FOLDER, OVERRIDE_MONIKER, Protocol + + +class ProtocolWithOverrides(Protocol): + """Model to describe a protocol that uses a base protocol to generate multiple Protocol classes""" + + overrides: list[str] = Field(description="A list of test options to iterate on, suitable to concatenate in a filename") + protocols: Optional[list[Protocol]] = Field(description="A list of the generated protocols", default=None) + + def __init__(self, **data: Any) -> None: + super().__init__(**data) + self.create_protocols() + + def create_protocols(self) -> None: + with open(self.file_path, "r") as file: + original_content = file.read() + protocols: list[Protocol] = [] + for override in self.overrides: + # Create the new file name with the override appended before the extension + new_file_stem: str = f"{self.file_stem}{OVERRIDE_MONIKER}{override}" + new_file_name = f"{new_file_stem}.{self.file_extension}" + # Create the full path for the new file + # all generated files live at files/protocols/$GENERATED_PROTOCOLS_FOLDER + new_file_path = Path(self.file_path.parent, GENERATED_PROTOCOLS_FOLDER, new_file_name) + # Prepare the override string to prepend + override_string = f'{self.override_variable_name} = "{override}"\n' + # Write the new file with the override string prepended + with open(new_file_path, "w") as new_file: + new_file.write(override_string + original_content) + + protocol = Protocol( + file_stem=new_file_stem, + file_extension=self.file_extension, + robot=self.robot, + app_error=self.app_error, + robot_error=self.robot_error, + app_analysis_error=self.app_analysis_error, + robot_analysis_error=self.robot_analysis_error, + custom_labware=self.custom_labware, + instruments=self.instruments, + modules=self.modules, + description=self.description, + expected_test_failure=self.expected_test_failure, + expected_test_reason=self.expected_test_reason, + from_override=True, + override_value=override, + ) + protocols.append(protocol) + self.protocols = protocols diff --git a/app-testing/automation/data/protocols.py b/app-testing/automation/data/protocols.py index ba091334ab2..136dacfe481 100644 --- a/app-testing/automation/data/protocols.py +++ b/app-testing/automation/data/protocols.py @@ -1,135 +1,114 @@ """Map for protocol files available for testing.""" + from automation.data.protocol import Protocol class Protocols: """Describe protocols available for testing.""" - # The name of the property must match the file_name property + # The name of the property must match the file_stem property # and be in protocol_files.names ########################################################################################################## # Begin JSON Protocols ################################################################################### ########################################################################################################## - OT2_P1000SLeft_None_6_1_SimpleTransfer: Protocol = Protocol( - file_name="OT2_P1000SLeft_None_6_1_SimpleTransfer", + OT2_S_v6_P1000S_None_SimpleTransfer: Protocol = Protocol( + file_stem="OT2_S_v6_P1000S_None_SimpleTransfer", file_extension="json", - protocol_name="Need Pipette", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - OT2_P20S_P300M_HS_6_1_HS_WithCollision_Error: Protocol = Protocol( - file_name="OT2_P20S_P300M_HS_6_1_HS_WithCollision_Error", + OT2_S_v6_P20S_P300M_TransferReTransferLiquid: Protocol = Protocol( + file_stem="OT2_S_v6_P20S_P300M_TransferReTransferLiquid", file_extension="json", - protocol_name="HS Collision", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, - description="""This protocol gives an error in PD.8-Channel pipette cannot access labware8-Channel pipettes cannot access labware or tip racks to the left or right of a Heater-Shaker GEN1 module. Move labware to a different slot to access it with an 8-Channel pipette.If you export it anyway there are NOT analysis errors in the app side analysis.TODO on if there are robot side analysis errors but do not expect them?""", # noqa: E501 ) - - OT2_P20S_P300M_NoMods_6_1_TransferReTransferLiquid: Protocol = Protocol( - file_name="OT2_P20S_P300M_NoMods_6_1_TransferReTransferLiquid", + OT2_X_v6_P20S_None_SimpleTransfer: Protocol = Protocol( + file_stem="OT2_X_v6_P20S_None_SimpleTransfer", file_extension="json", - protocol_name="Transfer- Multi liquid (retransfer)", - robot="OT-2", - app_error=False, - robot_error=False, - ) - OT2_P20SRight_None_6_1_SimpleTransferError: Protocol = Protocol( - file_name="OT2_P20SRight_None_6_1_SimpleTransferError", - file_extension="json", - protocol_name="Have Pipette", - robot="OT-2", + robot="OT2", app_error=True, robot_error=True, app_analysis_error="Cannot aspirate more than pipette max volume", robot_analysis_error="?", ) - OT2_P300M_P20S_HS_6_1_Smoke620release: Protocol = Protocol( - file_name="OT2_P300M_P20S_HS_6_1_Smoke620release", + OT2_S_v6_P300M_P20S_HS_Smoke620release: Protocol = Protocol( + file_stem="OT2_S_v6_P300M_P20S_HS_Smoke620release", file_extension="json", - protocol_name="H/S normal use", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - OT2_P300M_P20S_MM_HS_TD_TC_6_1_AllMods_Error: Protocol = Protocol( - file_name="OT2_P300M_P20S_MM_HS_TD_TC_6_1_AllMods_Error", + OT2_X_v6_P300M_P20S_HS_MM_TM_TC_AllMods: Protocol = Protocol( + file_stem="OT2_X_v6_P300M_P20S_HS_MM_TM_TC_AllMods", file_extension="json", - protocol_name="All mods", - robot="OT-2", + robot="OT2", app_error=True, robot_error=True, app_analysis_error="Heater-Shaker cannot open its labware latch while it is shaking.", robot_analysis_error="?", ) - OT2_P300M_P20S_MM_TM_TC1_5_2_6_PD40: Protocol = Protocol( - file_name="OT2_P300M_P20S_MM_TM_TC1_5_2_6_PD40", + OT2_S_v4_P300M_P20S_MM_TM_TC1_PD40: Protocol = Protocol( + file_stem="OT2_S_v4_P300M_P20S_MM_TM_TC1_PD40", file_extension="json", - protocol_name="script_pur_sample_1", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - OT2_P300M_P20S_MM_TM_TC1_5_2_6_PD40Error: Protocol = Protocol( - file_name="OT2_P300M_P20S_MM_TM_TC1_5_2_6_PD40Error", + OT2_X_v4_P300M_P20S_MM_TC1_TM_e2eTests: Protocol = Protocol( + file_stem="OT2_X_v4_P300M_P20S_MM_TC1_TM_e2eTests", file_extension="json", - protocol_name="script_pur_sample_1", - robot="OT-2", + robot="OT2", app_error=True, robot_error=True, app_analysis_error="Cannot aspirate more than pipette max volume", robot_analysis_error="?", ) - OT2_P300M_P20S_NoMod_6_1_MixTransferManyLiquids: Protocol = Protocol( - file_name="OT2_P300M_P20S_NoMod_6_1_MixTransferManyLiquids", + OT2_S_v6_P300M_P20S_MixTransferManyLiquids: Protocol = Protocol( + file_stem="OT2_S_v6_P300M_P20S_MixTransferManyLiquids", file_extension="json", - protocol_name="Mix/transfer- several liquids", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - OT2_P300M_P300S_HS_6_1_HS_NormalUseWithTransfer: Protocol = Protocol( - file_name="OT2_P300M_P300S_HS_6_1_HS_NormalUseWithTransfer", + OT2_S_v6_P300M_P300S_HS_HS_NormalUseWithTransfer: Protocol = Protocol( + file_stem="OT2_S_v6_P300M_P300S_HS_HS_NormalUseWithTransfer", file_extension="json", - protocol_name="H/S normal use", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - OT2_P300SG1_None_5_2_6_Gen1PipetteSimple: Protocol = Protocol( - file_name="OT2_P300SG1_None_5_2_6_Gen1PipetteSimple", + OT2_S_v3_P300SGen1_None_Gen1PipetteSimple: Protocol = Protocol( + file_stem="OT2_S_v3_P300SGen1_None_Gen1PipetteSimple", file_extension="json", - protocol_name="gen1 pipette", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - OT2_P300SLeft_MM_TM_TM_5_2_6_MOAMTemps: Protocol = Protocol( - file_name="OT2_P300SLeft_MM_TM_TM_5_2_6_MOAMTemps", + OT2_S_v4_P300S_None_MM_TM_TM_MOAMTemps: Protocol = Protocol( + file_stem="OT2_S_v4_P300S_None_MM_TM_TM_MOAMTemps", file_extension="json", - protocol_name="MoaM", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - Flex_P1000_96_Gripper_TC_TM_HS_AnalysisError_GripperCollisionWithTips: Protocol = Protocol( - file_name="Flex_P1000_96_Gripper_TC_TM_HS_AnalysisError_GripperCollisionWithTips", + Flex_X_v8_P1000_96_HS_GRIP_TC_TM_GripperCollisionWithTips: Protocol = Protocol( + file_stem="Flex_X_v8_P1000_96_HS_GRIP_TC_TM_GripperCollisionWithTips", file_extension="json", - protocol_name="Gripper Collision with Tips", robot="Flex", app_error=True, robot_error=False, @@ -140,382 +119,341 @@ class Protocols: # Begin Python Protocols ################################################################################### ############################################################################################################ - OT2_None_None_2_12_Python310SyntaxRobotAnalysisOnlyError: Protocol = Protocol( - file_name="OT2_None_None_2_12_Python310SyntaxRobotAnalysisOnlyError", + OT2_S_v2_12_NO_PIPETTES_Python310SyntaxRobotAnalysisOnlyError: Protocol = Protocol( + file_stem="OT2_S_v2_12_NO_PIPETTES_Python310SyntaxRobotAnalysisOnlyError", file_extension="py", - protocol_name="🛠 3.10 only Python 🛠", - robot="OT-2", + robot="OT2", app_error=False, robot_error=True, robot_analysis_error="?", ) - OT2_None_None_2_13_PythonSyntaxError: Protocol = Protocol( - file_name="OT2_None_None_2_13_PythonSyntaxError", + OT2_X_v2_13_None_None_PythonSyntaxError: Protocol = Protocol( + file_stem="OT2_X_v2_13_None_None_PythonSyntaxError", file_extension="py", - protocol_name="bad import", - robot="OT-2", + robot="OT2", app_error=True, robot_error=True, app_analysis_error="No module named 'superspecialmagic'", robot_analysis_error="?", ) - OT2_P10S_P300M_TC1_TM_MM_2_11_Swift: Protocol = Protocol( - file_name="OT2_P10S_P300M_TC1_TM_MM_2_11_Swift", + OT2_S_v2_11_P10S_P300M_MM_TC1_TM_Swift: Protocol = Protocol( + file_stem="OT2_S_v2_11_P10S_P300M_MM_TC1_TM_Swift", file_extension="py", - protocol_name="OT2_P10S_P300M_TC1_TM_MM_2_11_Swift.py", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - OT2_P20S_None_2_7_Walkthrough: Protocol = Protocol( - file_name="OT2_P20S_None_2_7_Walkthrough", + OT2_S_v2_7_P20S_None_Walkthrough: Protocol = Protocol( + file_stem="OT2_S_v2_7_P20S_None_Walkthrough", file_extension="py", - protocol_name="OT-2 Guided Walk-through", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - OT2_P300M_P20S_2_16_aspirateDispenseMix0Volume: Protocol = Protocol( - file_name="OT2_P300M_P20S_2_16_aspirateDispenseMix0Volume", + OT2_S_v2_16_P300M_P20S_aspirateDispenseMix0Volume: Protocol = Protocol( + file_stem="OT2_S_v2_16_P300M_P20S_aspirateDispenseMix0Volume", file_extension="py", - protocol_name="QA Protocol - API 2.16 - Aspirate Dispense Mix with 0 Volume", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - OT2_P300M_P20S_None_2_12_FailOnRun: Protocol = Protocol( - file_name="OT2_P300M_P20S_None_2_12_FailOnRun", + OT2_S_v2_12_P300M_P20S_FailOnRun: Protocol = Protocol( + file_stem="OT2_S_v2_12_P300M_P20S_FailOnRun", file_extension="py", - protocol_name="Will fail on run", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - OT2_P300M_P20S_TC_HS_TM_2_13_SmokeTestV3: Protocol = Protocol( - file_name="OT2_P300M_P20S_TC_HS_TM_2_13_SmokeTestV3", + OT2_S_v2_13_P300M_P20S_HS_TC_TM_SmokeTestV3: Protocol = Protocol( + file_stem="OT2_S_v2_13_P300M_P20S_HS_TC_TM_SmokeTestV3", file_extension="py", - protocol_name="🛠️ 2.13 Smoke Test V3 🪄", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, custom_labware=["cpx_4_tuberack_100ul"], ) - OT2_P300M_P20S_TC_HS_TM_2_14_SmokeTestV3: Protocol = Protocol( - file_name="OT2_P300M_P20S_TC_HS_TM_2_14_SmokeTestV3", + OT2_S_v2_14_P300M_P20S_HS_TC_TM_SmokeTestV3: Protocol = Protocol( + file_stem="OT2_S_v2_14_P300M_P20S_HS_TC_TM_SmokeTestV3", file_extension="py", - protocol_name="🛠️ 2.14 Smoke Test V3 🪄", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, custom_labware=["cpx_4_tuberack_100ul"], ) - OT2_P300M_P20S_TC_HS_TM_2_15_SmokeTestV3: Protocol = Protocol( - file_name="OT2_P300M_P20S_TC_HS_TM_2_15_SmokeTestV3", + OT2_S_v2_15_P300M_P20S_HS_TC_TM_SmokeTestV3: Protocol = Protocol( + file_stem="OT2_S_v2_15_P300M_P20S_HS_TC_TM_SmokeTestV3", file_extension="py", - protocol_name="🛠️ 2.15 Smoke Test V3 🪄", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, custom_labware=["cpx_4_tuberack_100ul"], ) - OT2_P300M_P20S_TC_HS_TM_2_16_SmokeTestV3: Protocol = Protocol( - file_name="OT2_P300M_P20S_TC_HS_TM_2_16_SmokeTestV3", + OT2_S_v2_16_P300M_P20S_HS_TC_TM_SmokeTestV3: Protocol = Protocol( + file_stem="OT2_S_v2_16_P300M_P20S_HS_TC_TM_SmokeTestV3", file_extension="py", - protocol_name="🛠️ 2.16 Smoke Test V3 🪄", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, custom_labware=["cpx_4_tuberack_100ul"], ) - OT2_P300M_P20S_TC_HS_TM_2_17_SmokeTestV3: Protocol = Protocol( - file_name="OT2_P300M_P20S_TC_HS_TM_2_17_SmokeTestV3", + OT2_S_v2_17_P300M_P20S_HS_TC_TM_SmokeTestV3: Protocol = Protocol( + file_stem="OT2_S_v2_17_P300M_P20S_HS_TC_TM_SmokeTestV3", file_extension="py", - protocol_name="🛠️ 2.17 Smoke Test V3 🪄", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - OT2_P300M_P20S_TC_MM_TM_2_13_Smoke620Release: Protocol = Protocol( - file_name="OT2_P300M_P20S_TC_MM_TM_2_13_Smoke620Release", + OT2_S_v2_13_P300M_P20S_MM_TC_TM_Smoke620Release: Protocol = Protocol( + file_stem="OT2_S_v2_13_P300M_P20S_MM_TC_TM_Smoke620Release", file_extension="py", - protocol_name="🛠 Logo-Modules-CustomLabware 🛠", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, custom_labware=["cpx_4_tuberack_100ul"], ) - OT2_P300MLeft_MM_TM_2_4_Zymo: Protocol = Protocol( - file_name="OT2_P300MLeft_MM_TM_2_4_Zymo", + OT2_S_v2_4_P300M_None_MM_TM_Zymo: Protocol = Protocol( + file_stem="OT2_S_v2_4_P300M_None_MM_TM_Zymo", file_extension="py", - protocol_name="Zymo Direct-zol96 Magbead RNA", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - OT2_P300S_Thermocycler_Moam_Error: Protocol = Protocol( - file_name="OT2_P300S_Thermocycler_Moam_Error", + OT2_X_v2_11_P300S_TC1_TC2_ThermocyclerMoamError: Protocol = Protocol( + file_stem="OT2_X_v2_11_P300S_TC1_TC2_ThermocyclerMoamError", file_extension="py", - protocol_name="OT2_P300S_Thermocycler_Moam_Error.py", - robot="OT-2", + robot="OT2", app_error=True, robot_error=True, app_analysis_error="DeckConflictError [line 19]: thermocyclerModuleV2 in slot 7 prevents thermocyclerModuleV1 from using slot 7.", # noqa: E501 robot_analysis_error="?", ) - OT2_P300S_Twinning_Error: Protocol = Protocol( - file_name="OT2_P300S_Twinning_Error", + OT2_X_v2_7_P300S_TwinningError: Protocol = Protocol( + file_stem="OT2_X_v2_7_P300S_TwinningError", file_extension="py", - protocol_name="My Protocol", - robot="OT-2", + robot="OT2", app_error=True, robot_error=True, app_analysis_error="AttributeError [line 24]: 'InstrumentContext' object has no attribute 'pair_with'", robot_analysis_error="?", ) - OT2_P300SLeft_MM1_MM_2_2_EngageMagHeightFromBase: Protocol = Protocol( - file_name="OT2_P300SLeft_MM1_MM_2_2_EngageMagHeightFromBase", + OT2_S_v2_2_P300S_None_MM1_MM2_EngageMagHeightFromBase: Protocol = Protocol( + file_stem="OT2_S_v2_2_P300S_None_MM1_MM2_EngageMagHeightFromBase", file_extension="py", - protocol_name="OT2_P300SLeft_MM1_MM_2_2_EngageMagHeightFromBase.py", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - OT2_P300SLeft_MM1_MM_TM_2_3_Mix: Protocol = Protocol( - file_name="OT2_P300SLeft_MM1_MM_TM_2_3_Mix", + OT2_S_v2_3_P300S_None_MM1_MM2_TM_Mix: Protocol = Protocol( + file_stem="OT2_S_v2_3_P300S_None_MM1_MM2_TM_Mix", file_extension="py", - protocol_name="OT2_P300SLeft_MM1_MM_TM_2_3_Mix.py", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - OT2_P300M_P20S_TC_HS_TM_2_16_aspirateDispenseMix0Volume: Protocol = Protocol( - file_name="OT2_P300M_P20S_TC_HS_TM_2_16_aspirateDispenseMix0Volume", + OT2_S_v2_16_P300M_P20S_HS_TC_TM_aspirateDispenseMix0Volume: Protocol = Protocol( + file_stem="OT2_S_v2_16_P300M_P20S_HS_TC_TM_aspirateDispenseMix0Volume", file_extension="py", - protocol_name="OT2_P300M_P20S_TC_HS_TM_2_16_aspirateDispenseMix0Volume.py", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - OT2_P300M_P20S_TC_HS_TM_2_15_dispense_changes: Protocol = Protocol( - file_name="OT2_P300M_P20S_TC_HS_TM_2_15_dispense_changes", + OT2_S_v2_15_P300M_P20S_HS_TC_TM_dispense_changes: Protocol = Protocol( + file_stem="OT2_S_v2_15_P300M_P20S_HS_TC_TM_dispense_changes", file_extension="py", - protocol_name="OT2_P300M_P20S_TC_HS_TM_2_15_dispense_changes.py", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - OT2_P300M_P20S_TC_HS_TM_2_16_dispense_changes: Protocol = Protocol( - file_name="OT2_P300M_P20S_TC_HS_TM_2_16_dispense_changes", + OT2_S_v2_16_P300M_P20S_HS_TC_TM_dispense_changes: Protocol = Protocol( + file_stem="OT2_S_v2_16_P300M_P20S_HS_TC_TM_dispense_changes", file_extension="py", - protocol_name="OT2_P300M_P20S_TC_HS_TM_2_16_dispense_changes.py", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - OT2_P300M_P20S_TC_HS_TM_2_17_dispense_changes: Protocol = Protocol( - file_name="OT2_P300M_P20S_TC_HS_TM_2_17_dispense_changes", + OT2_S_v2_17_P300M_P20S_HS_TC_TM_dispense_changes: Protocol = Protocol( + file_stem="OT2_S_v2_17_P300M_P20S_HS_TC_TM_dispense_changes", file_extension="py", - protocol_name="OT2_P300M_P20S_TC_HS_TM_2_17_dispense_changes.py", - robot="OT-2", + robot="OT2", app_error=True, robot_error=False, app_analysis_error="ValueError [line 15]: Cannot dispense more than pipette max volume", # noqa: E501 ) - OT2_None_None_TC_2_14_VerifyThermocyclerLoadedSlots: Protocol = Protocol( - file_name="OT2_None_None_TC_2_14_VerifyThermocyclerLoadedSlots", + OT2_S_v2_14_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots: Protocol = Protocol( + file_stem="OT2_S_v2_14_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots", file_extension="py", - protocol_name="OT2_None_None_TC_2_14_VerifyThermocyclerLoadedSlots.py", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - OT2_None_None_TC_2_15_VerifyThermocyclerLoadedSlots: Protocol = Protocol( - file_name="OT2_None_None_TC_2_15_VerifyThermocyclerLoadedSlots", + OT2_S_v2_15_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots: Protocol = Protocol( + file_stem="OT2_S_v2_15_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots", file_extension="py", - protocol_name="OT2_None_None_TC_2_15_VerifyThermocyclerLoadedSlots.py", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - OT2_None_None_TC_2_16_VerifyThermocyclerLoadedSlots: Protocol = Protocol( - file_name="OT2_None_None_TC_2_16_VerifyThermocyclerLoadedSlots", + OT2_S_v2_16_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots: Protocol = Protocol( + file_stem="OT2_S_v2_16_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots", file_extension="py", - protocol_name="OT2_None_None_TC_2_16_VerifyThermocyclerLoadedSlots.py", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - OT2_None_None_TC_2_17_VerifyThermocyclerLoadedSlots: Protocol = Protocol( - file_name="OT2_None_None_TC_2_17_VerifyThermocyclerLoadedSlots", + OT2_S_v2_17_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots: Protocol = Protocol( + file_stem="OT2_S_v2_17_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots", file_extension="py", - protocol_name="OT2_None_None_TC_2_17_VerifyThermocyclerLoadedSlots.py", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin1: Protocol = Protocol( - file_name="OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin1", + OT2_X_v2_16_None_None_HS_HeaterShakerConflictWithTrashBin1: Protocol = Protocol( + file_stem="OT2_X_v2_16_None_None_HS_HeaterShakerConflictWithTrashBin1", file_extension="py", - protocol_name="OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin1.py", - robot="OT-2", + robot="OT2", app_error=True, robot_error=False, app_analysis_error="DeckConflictError [line 19]: trash_bin in slot 12 prevents heater_shaker in slot 11 from using slot 11.", # noqa: E501 ) - OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin2: Protocol = Protocol( - file_name="OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin2", + OT2_X_v2_16_None_None_HS_HeaterShakerConflictWithTrashBin2: Protocol = Protocol( + file_stem="OT2_X_v2_16_None_None_HS_HeaterShakerConflictWithTrashBin2", file_extension="py", - protocol_name="OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin2.py", - robot="OT-2", + robot="OT2", app_error=True, robot_error=False, app_analysis_error="DeckConflictError [line 19]: trash_bin in slot 12 prevents heater_shaker in slot 11 from using slot 11.", # noqa: E501 ) - OT2_None_None_2_16_verifyDoesNotDeadlock: Protocol = Protocol( - file_name="OT2_None_None_2_16_verifyDoesNotDeadlock", + OT2_S_v2_16_NO_PIPETTES_verifyDoesNotDeadlock: Protocol = Protocol( + file_stem="OT2_S_v2_16_NO_PIPETTES_verifyDoesNotDeadlock", file_extension="py", - protocol_name="OT2_None_None_2_16_verifyDoesNotDeadlock.py", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - OT2_P300S_None_2_16_verifyNoFloatingPointErrorInPipetting: Protocol = Protocol( - file_name="OT2_P300S_None_2_16_verifyNoFloatingPointErrorInPipetting", + OT2_S_v2_16_P300S_None_verifyNoFloatingPointErrorInPipetting: Protocol = Protocol( + file_stem="OT2_S_v2_16_P300S_None_verifyNoFloatingPointErrorInPipetting", file_extension="py", - protocol_name="OT2_P300S_None_2_16_verifyNoFloatingPointErrorInPipetting.py", - robot="OT-2", + robot="OT2", app_error=False, robot_error=False, ) - Flex_P100_96_HS_TM_2_15_Quick_Zymo_RNA_Bacteria: Protocol = Protocol( - file_name="Flex_P100_96_HS_TM_2_15_Quick_Zymo_RNA_Bacteria", + Flex_S_v2_15_P1000_96_GRIP_HS_TM_QuickZymoMagbeadRNAExtraction: Protocol = Protocol( + file_stem="Flex_S_v2_15_P1000_96_GRIP_HS_TM_QuickZymoMagbeadRNAExtraction", file_extension="py", - protocol_name="Quick Zymo Magbead RNA Extraction with Lysis: Bacteria 96 Channel Deletion Test", robot="Flex", app_error=False, robot_error=False, custom_labware=["opentrons_ot3_96_tiprack_1000ul_rss"], ) - Flex_P1000_96_HS_TM_MM_2_15_ABR5_6_HDQ_Bacteria_ParkTips_96_channel: Protocol = Protocol( - file_name="Flex_P1000_96_HS_TM_MM_2_15_ABR5_6_HDQ_Bacteria_ParkTips_96_channel", + Flex_S_v2_15_P1000_96_GRIP_HS_MB_TM_OmegaHDQDNAExtraction: Protocol = Protocol( + file_stem="Flex_S_v2_15_P1000_96_GRIP_HS_MB_TM_OmegaHDQDNAExtraction", file_extension="py", - protocol_name="Omega HDQ DNA Extraction: Bacteria 96 FOR ABR TESTING", robot="Flex", app_error=False, robot_error=False, custom_labware=["opentrons_ot3_96_tiprack_1000ul_rss"], ) - Flex_P1000_96_HS_TM_MM_2_15_MagMaxRNACells96Ch: Protocol = Protocol( - file_name="Flex_P1000_96_HS_TM_MM_2_15_MagMaxRNACells96Ch", + Flex_S_v2_15_P1000_96_GRIP_HS_MB_TM_MagMaxRNAExtraction: Protocol = Protocol( + file_stem="Flex_S_v2_15_P1000_96_GRIP_HS_MB_TM_MagMaxRNAExtraction", file_extension="py", - protocol_name="MagMax RNA Extraction: Cells 96 ABR TESTING", robot="Flex", app_error=False, robot_error=False, custom_labware=["opentrons_ot3_96_tiprack_200ul_rss"], ) - Flex_P1000_96_HS_TM_TC_MM_2_15_ABR5_6_Illumina_DNA_Prep_96x_Head_PART_III: Protocol = Protocol( - file_name="Flex_P1000_96_HS_TM_TC_MM_2_15_ABR5_6_Illumina_DNA_Prep_96x_Head_PART_III", + Flex_S_v2_15_P1000_96_GRIP_HS_MB_TC_TM_IlluminaDNAPrep96PART3: Protocol = Protocol( + file_stem="Flex_S_v2_15_P1000_96_GRIP_HS_MB_TC_TM_IlluminaDNAPrep96PART3", file_extension="py", - protocol_name="Illumina DNA Prep 96x Head PART III", robot="Flex", app_error=False, robot_error=False, custom_labware=["opentrons_ot3_96_tiprack_200ul_rss", "opentrons_ot3_96_tiprack_50ul_rss"], ) - Flex_P1000_96_None_2_15_ABR5_6_IDT_xGen_EZ_96x_Head_PART_I_III_ABR: Protocol = Protocol( - file_name="Flex_P1000_96_None_2_15_ABR5_6_IDT_xGen_EZ_96x_Head_PART_I_III_ABR", + Flex_S_v2_15_P1000_96_GRIP_HS_MB_TC_TM_IDTXgen96Part1to3: Protocol = Protocol( + file_stem="Flex_S_v2_15_P1000_96_GRIP_HS_MB_TC_TM_IDTXgen96Part1to3", file_extension="py", - protocol_name="IDT xGen EZ 96x Head PART I-III ABR", robot="Flex", app_error=False, robot_error=False, custom_labware=["opentrons_ot3_96_tiprack_50ul_rss", "opentrons_ot3_96_tiprack_200ul_rss"], ) - Flex_P1000MLeft_P50MRight_HS_MM_TC_TM_2_15_ABR3_Illumina_DNA_Enrichment_v4: Protocol = Protocol( - file_name="Flex_P1000MLeft_P50MRight_HS_MM_TC_TM_2_15_ABR3_Illumina_DNA_Enrichment_v4", + Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAEnrichmentv4: Protocol = Protocol( + file_stem="Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAEnrichmentv4", file_extension="py", - protocol_name="Illumina DNA Enrichment v4", robot="Flex", app_error=False, robot_error=False, ) - Flex_P1000MLeft_P50MRight_HS_MM_TC_TM_2_15_ABR3_Illumina_DNA_Enrichment: Protocol = Protocol( - file_name="Flex_P1000MLeft_P50MRight_HS_MM_TC_TM_2_15_ABR3_Illumina_DNA_Enrichment", + Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAEnrichment: Protocol = Protocol( + file_stem="Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAEnrichment", file_extension="py", - protocol_name="Illumina DNA Enrichment", robot="Flex", app_error=False, robot_error=False, ) - Flex_P1000MLeft_P50MRight_HS_TM_MM_TC_2_15_ABR4_Illumina_DNA_Prep_24x: Protocol = Protocol( - file_name="Flex_P1000MLeft_P50MRight_HS_TM_MM_TC_2_15_ABR4_Illumina_DNA_Prep_24x", + Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAPrep24x: Protocol = Protocol( + file_stem="Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAPrep24x", file_extension="py", - protocol_name="Illumina DNA Prep 24x", robot="Flex", app_error=False, robot_error=False, ) - Flex_P1000SRight_None_2_15_ABR_Simple_Normalize_Long_Right: Protocol = Protocol( - file_name="Flex_P1000SRight_None_2_15_ABR_Simple_Normalize_Long_Right", + Flex_S_v2_15_P1000S_None_SimpleNormalizeLongRight: Protocol = Protocol( + file_stem="Flex_S_v2_15_P1000S_None_SimpleNormalizeLongRight", file_extension="py", - protocol_name="Flex ABR Simple Normalize Long", robot="Flex", app_error=False, robot_error=False, custom_labware=["opentrons_ot3_96_tiprack_200ul_rss"], ) - Flex_P50MLeft_P1000MRight_None_2_15_ABRKAPALibraryQuantLongv2: Protocol = Protocol( - file_name="Flex_P50MLeft_P1000MRight_None_2_15_ABRKAPALibraryQuantLongv2", + Flex_S_v2_15_P50M_P1000M_KAPALibraryQuantLongv2: Protocol = Protocol( + file_stem="Flex_S_v2_15_P50M_P1000M_KAPALibraryQuantLongv2", file_extension="py", - protocol_name="Flex ABR KAPA Library Quant v2", robot="Flex", app_error=False, robot_error=False, ) - Flex_None_None_2_16_AnalysisError_TrashBinInCol2: Protocol = Protocol( - file_name="Flex_None_None_2_16_AnalysisError_TrashBinInCol2", + Flex_X_v2_16_NO_PIPETTES_TrashBinInCol2: Protocol = Protocol( + file_stem="Flex_X_v2_16_NO_PIPETTES_TrashBinInCol2", file_extension="py", - protocol_name="QA Protocol - Analysis Error - Trash Bin in Column 2", robot="Flex", app_error=True, robot_error=False, app_analysis_error="InvalidTrashBinLocationError [line 15]: Invalid location for trash bin: C2. Valid slots: Any slot in column 1 or 3.", # noqa: E501 ) - Flex_None_None_2_16_AnalysisError_TrashBinInStagingAreaCol3: Protocol = Protocol( - file_name="Flex_None_None_2_16_AnalysisError_TrashBinInStagingAreaCol3", + Flex_X_v2_16_NO_PIPETTES_TrashBinInStagingAreaCol3: Protocol = Protocol( + file_stem="Flex_X_v2_16_NO_PIPETTES_TrashBinInStagingAreaCol3", file_extension="py", - protocol_name="QA Protocol - Analysis Error - Trash Bin in Staging Area Column 3", robot="Flex", app_error=True, robot_error=False, @@ -524,30 +462,27 @@ class Protocols: expected_test_reason="Analysis does not throw error when modules or fixtures are in staging area column 3.", # noqa: E501 ) - Flex_None_None_2_16_AnalysisError_TrashBinInStagingAreaCol4: Protocol = Protocol( - file_name="Flex_None_None_2_16_AnalysisError_TrashBinInStagingAreaCol4", + Flex_X_v2_16_NO_PIPETTES_TrashBinInStagingAreaCol4: Protocol = Protocol( + file_stem="Flex_X_v2_16_NO_PIPETTES_TrashBinInStagingAreaCol4", file_extension="py", - protocol_name="QA Protocol - Analysis Error - Trash Bin in Staging Area Column 4", robot="Flex", app_error=True, robot_error=False, app_analysis_error="ValueError [line 15]: Staging areas not permitted for trash bin.", # noqa: E501 ) - Flex_P1000_96_2_16_AnalysisError_DropTipsWithNoTrash: Protocol = Protocol( - file_name="Flex_P1000_96_2_16_AnalysisError_DropTipsWithNoTrash", + Flex_X_v2_16_P1000_96_DropTipsWithNoTrash: Protocol = Protocol( + file_stem="Flex_X_v2_16_P1000_96_DropTipsWithNoTrash", file_extension="py", - protocol_name="QA Protocol - Analysis Error - Drop Tips with no Trash", robot="Flex", app_error=True, robot_error=False, app_analysis_error="NoTrashDefinedError [line 24]: Error 4000 GENERAL_ERROR (NoTrashDefinedError): No trash container has been defined in this protocol.", # noqa: E501 ) - Flex_None_None_TM_2_16_AnalysisError_ModuleInStagingAreaCol3: Protocol = Protocol( - file_name="Flex_None_None_TM_2_16_AnalysisError_ModuleInStagingAreaCol3", + Flex_X_v2_16_NO_PIPETTES_TM_ModuleInStagingAreaCol3: Protocol = Protocol( + file_stem="Flex_X_v2_16_NO_PIPETTES_TM_ModuleInStagingAreaCol3", file_extension="py", - protocol_name="QA Protocol - Analysis Error - Module in Staging Area Column 3", robot="Flex", app_error=True, robot_error=False, @@ -556,230 +491,254 @@ class Protocols: expected_test_reason="Analysis does not throw error when modules or fixtures are in staging area column 3.", # noqa: E501 ) - Flex_None_None_TM_2_16_AnalysisError_ModuleInStagingAreaCol4: Protocol = Protocol( - file_name="Flex_None_None_TM_2_16_AnalysisError_ModuleInStagingAreaCol4", + Flex_X_v2_16_NO_PIPETTES_TM_ModuleInStagingAreaCol4: Protocol = Protocol( + file_stem="Flex_X_v2_16_NO_PIPETTES_TM_ModuleInStagingAreaCol4", file_extension="py", - protocol_name="QA Protocol - Analysis Error - Module in Staging Area Column 4", robot="Flex", app_error=True, robot_error=False, app_analysis_error="ValueError [line 15]: Cannot load a module onto a staging slot.", # noqa: E501 ) - Flex_P1000_96_TM_2_16_AnalysisError_ModuleAndWasteChuteConflict: Protocol = Protocol( - file_name="Flex_P1000_96_TM_2_16_AnalysisError_ModuleAndWasteChuteConflict", + Flex_X_v2_16_P1000_96_TM_ModuleAndWasteChuteConflict: Protocol = Protocol( + file_stem="Flex_X_v2_16_P1000_96_TM_ModuleAndWasteChuteConflict", file_extension="py", - protocol_name="QA Protocol - Analysis Error - Module and Waste Chute Conflict", robot="Flex", app_error=True, robot_error=False, app_analysis_error="ProtocolCommandFailedError [line 25]: Error 4000 GENERAL_ERROR (ProtocolCommandFailedError): IncompatibleAddressableAreaError: Cannot use Waste Chute, not compatible with one or more of the following fixtures: Slot D3", # noqa: E501 ) - Flex_None_None_2_16_AnalysisError_AccessToFixedTrashProp: Protocol = Protocol( - file_name="Flex_None_None_2_16_AnalysisError_AccessToFixedTrashProp", + Flex_X_v2_16_NO_PIPETTES_AccessToFixedTrashProp: Protocol = Protocol( + file_stem="Flex_X_v2_16_NO_PIPETTES_AccessToFixedTrashProp", file_extension="py", - protocol_name="QA Protocol - Analysis Error - Access to Fixed Trash Property", robot="Flex", app_error=True, robot_error=False, app_analysis_error="APIVersionError [line 15]: Fixed Trash is not supported on Flex protocols in API Version 2.16 and above.", # noqa: E501 ) - Flex_P1000_96_GRIPPER_2_16_AnalysisError_DropLabwareIntoTrashBin: Protocol = Protocol( - file_name="Flex_P1000_96_GRIPPER_2_16_AnalysisError_DropLabwareIntoTrashBin", + Flex_X_v2_16_P1000_96_GRIP_DropLabwareIntoTrashBin: Protocol = Protocol( + file_stem="Flex_X_v2_16_P1000_96_GRIP_DropLabwareIntoTrashBin", file_extension="py", - protocol_name="QA Protocol - Analysis Error - Drop Labware in Trash Bin", robot="Flex", app_error=True, robot_error=False, app_analysis_error="ProtocolCommandFailedError [line 20]: Error 4000 GENERAL_ERROR (ProtocolCommandFailedError): IncompatibleAddressableAreaError: Cannot use Slot C3, not compatible with one or more of the following fixtures: Trash Bin in C3", # noqa: E501 ) - Flex_P300Gen2_None_2_16_AnalysisError_OT2PipetteInFlexProtocol: Protocol = Protocol( - file_name="Flex_P300Gen2_None_2_16_AnalysisError_OT2PipetteInFlexProtocol", + Flex_X_v2_16_P300MGen2_None_OT2PipetteInFlexProtocol: Protocol = Protocol( + file_stem="Flex_X_v2_16_P300MGen2_None_OT2PipetteInFlexProtocol", file_extension="py", - protocol_name="QA Protocol - Analysis Error - OT-2 Pipette in Flex Protocol", robot="Flex", app_error=True, robot_error=False, app_analysis_error="ProtocolCommandFailedError [line 22]: Error 4000 GENERAL_ERROR (ProtocolCommandFailedError): InvalidSpecificationForRobotTypeError: Cannot load a Gen2 pipette on a Flex.", # noqa: E501 ) - Flex_None_None_MM_2_16_AnalysisError_MagneticModuleInFlexProtocol: Protocol = Protocol( - file_name="Flex_None_None_MM_2_16_AnalysisError_MagneticModuleInFlexProtocol", + Flex_X_v2_16_NO_PIPETTES_MM_MagneticModuleInFlexProtocol: Protocol = Protocol( + file_stem="Flex_X_v2_16_NO_PIPETTES_MM_MagneticModuleInFlexProtocol", file_extension="py", - protocol_name="QA Protocol - Analysis Error - Magnetic Module in Flex Protocol", robot="Flex", app_error=True, robot_error=False, app_analysis_error="ValueError [line 15]: A magneticModuleType cannot be loaded into slot C1", # noqa: E501 ) - Flex_None_None_TM_2_16_AnalysisError_ModuleInCol2: Protocol = Protocol( - file_name="Flex_None_None_TM_2_16_AnalysisError_ModuleInCol2", + Flex_X_v2_16_NO_PIPETTES_TM_ModuleInCol2: Protocol = Protocol( + file_stem="Flex_X_v2_16_NO_PIPETTES_TM_ModuleInCol2", file_extension="py", - protocol_name="QA Protocol - Analysis Error - Module in Column 2", robot="Flex", app_error=True, robot_error=False, app_analysis_error="ValueError [line 15]: A temperatureModuleType cannot be loaded into slot C2", # noqa: E501 ) - Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoFixtures: Protocol = Protocol( - file_name="Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoFixtures", + Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_DeckConfiguration1NoFixtures: Protocol = Protocol( + file_stem="Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_DeckConfiguration1NoFixtures", file_extension="py", - protocol_name="QA Protocol - Deck Configuration 1 - No Fixtures", robot="Flex", app_error=False, robot_error=False, ) - Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoModules: Protocol = Protocol( - file_name="Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoModules", + Flex_S_v2_16_P1000_96_GRIP_DeckConfiguration1NoModules: Protocol = Protocol( + file_stem="Flex_S_v2_16_P1000_96_GRIP_DeckConfiguration1NoModules", file_extension="py", - protocol_name="QA Protocol - Deck Configuration 1 - No Modules", robot="Flex", app_error=False, robot_error=False, ) - Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoModulesNoFixtures: Protocol = Protocol( - file_name="Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoModulesNoFixtures", + Flex_S_v2_16_P1000_96_GRIP_DeckConfiguration1NoModulesNoFixtures: Protocol = Protocol( + file_stem="Flex_S_v2_16_P1000_96_GRIP_DeckConfiguration1NoModulesNoFixtures", file_extension="py", - protocol_name="QA Protocol - Deck Configuration 1 - No Modules or Fixtures", robot="Flex", app_error=False, robot_error=False, ) - Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1: Protocol = Protocol( - file_name="Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1", + Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_DeckConfiguration1: Protocol = Protocol( + file_stem="Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_DeckConfiguration1", file_extension="py", - protocol_name="QA Protocol - Deck Configuration 1", robot="Flex", app_error=False, robot_error=False, ) - Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_Smoke: Protocol = Protocol( - file_name="Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_Smoke", + Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_Smoke: Protocol = Protocol( + file_stem="Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_Smoke", file_extension="py", - protocol_name="QA Protocol - MEGAAA PROTOCOL - LETS BREAK, I MEAN TEST, EVERYTHING!!!!!", robot="Flex", app_error=False, robot_error=False, ) - Flex_None_None_TC_2_14_verifyThermocyclerLoadedSlots: Protocol = Protocol( - file_name="Flex_None_None_TC_2_14_verifyThermocyclerLoadedSlots", + Flex_S_v2_15_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots: Protocol = Protocol( + file_stem="Flex_S_v2_15_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots", file_extension="py", - protocol_name="QA Protocol - Verify Thermocycler Loaded Slots", robot="Flex", app_error=False, robot_error=False, ) - Flex_None_None_TC_2_15_verifyThermocyclerLoadedSlots: Protocol = Protocol( - file_name="Flex_None_None_TC_2_15_verifyThermocyclerLoadedSlots", + Flex_S_v2_16_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots: Protocol = Protocol( + file_stem="Flex_S_v2_16_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots", file_extension="py", - protocol_name="QA Protocol - Verify Thermocycler Loaded Slots", robot="Flex", app_error=False, robot_error=False, ) - Flex_None_None_TC_2_16_verifyThermocyclerLoadedSlots: Protocol = Protocol( - file_name="Flex_None_None_TC_2_16_verifyThermocyclerLoadedSlots", + Flex_S_v2_17_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots: Protocol = Protocol( + file_stem="Flex_S_v2_17_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots", file_extension="py", - protocol_name="QA Protocol - Verify Thermocycler Loaded Slots", robot="Flex", app_error=False, robot_error=False, ) - Flex_None_None_TC_2_17_verifyThermocyclerLoadedSlots: Protocol = Protocol( - file_name="Flex_None_None_TC_2_17_verifyThermocyclerLoadedSlots", + Flex_X_v2_16_NO_PIPETTES_TC_TrashBinAndThermocyclerConflict: Protocol = Protocol( + file_stem="Flex_X_v2_16_NO_PIPETTES_TC_TrashBinAndThermocyclerConflict", file_extension="py", - protocol_name="QA Protocol - Verify Thermocycler Loaded Slots", - robot="Flex", - app_error=False, - robot_error=False, - ) - - Flex_None_None_TC_2_16_AnalysisError_TrashBinAndThermocyclerConflict: Protocol = Protocol( - file_name="Flex_None_None_TC_2_16_AnalysisError_TrashBinAndThermocyclerConflict", - file_extension="py", - protocol_name="Flex_None_None_TC_2_16_AnalysisError_TrashBinAndThermocyclerConflict", robot="Flex", app_error=True, robot_error=False, app_analysis_error="IncompatibleAddressableAreaError [line 15]: Cannot use Trash Bin in C3, not compatible with one or more of the following fixtures: Thermocycler in C3", # noqa: E501 ) - Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLidClips: Protocol = Protocol( - file_name="Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLidClips", + Flex_X_v2_16_P1000_96_TC_pipetteCollisionWithThermocyclerLidClips: Protocol = Protocol( + file_stem="Flex_X_v2_16_P1000_96_TC_pipetteCollisionWithThermocyclerLidClips", file_extension="py", - protocol_name="Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLidClips", robot="Flex", app_error=True, robot_error=False, app_analysis_error="IncompatibleAddressableAreaError [line 15]: Cannot use Slot C3, not compatible with one or more of the following fixtures: Thermocycler in C3", # noqa: E501 ) - Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLid: Protocol = Protocol( - file_name="Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLid", + Flex_X_v2_16_P1000_96_TC_pipetteCollisionWithThermocyclerLid: Protocol = Protocol( + file_stem="Flex_X_v2_16_P1000_96_TC_pipetteCollisionWithThermocyclerLid", file_extension="py", - protocol_name="Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLid", robot="Flex", app_error=True, robot_error=False, app_analysis_error="IncompatibleAddressableAreaError [line 15]: Cannot use Slot C3, not compatible with one or more of the following fixtures: Thermocycler in C3", # noqa: E501 ) - Flex_P1000_96_TC_2_16_PartialTipPickupSingle: Protocol = Protocol( - file_name="Flex_P1000_96_TC_2_16_PartialTipPickupSingle", + Flex_S_v2_16_P1000_96_TC_PartialTipPickupSingle: Protocol = Protocol( + file_stem="Flex_S_v2_16_P1000_96_TC_PartialTipPickupSingle", file_extension="py", - protocol_name="Partial Tip Pickup Single", robot="Flex", app_error=False, robot_error=False, ) - Flex_P1000_96_TC_2_16_PartialTipPickupColumn: Protocol = Protocol( - file_name="Flex_P1000_96_TC_2_16_PartialTipPickupColumn", + Flex_S_v2_16_P1000_96_TC_PartialTipPickupColumn: Protocol = Protocol( + file_stem="Flex_S_v2_16_P1000_96_TC_PartialTipPickupColumn", file_extension="py", - protocol_name="Partial Tip Pickup Column", robot="Flex", app_error=False, robot_error=False, ) - Flex_P1000_96_TC_2_16_AnalysisError_PartialTipPickupTryToReturnTip: Protocol = Protocol( - file_name="Flex_P1000_96_TC_2_16_AnalysisError_PartialTipPickupTryToReturnTip", + Flex_X_v2_16_P1000_96_TC_PartialTipPickupTryToReturnTip: Protocol = Protocol( + file_stem="Flex_X_v2_16_P1000_96_TC_PartialTipPickupTryToReturnTip", file_extension="py", - protocol_name="Partial Tip Pickup Try to Return Tip", robot="Flex", app_error=True, robot_error=False, app_analysis_error="ValueError [line 15]: Cannot return tip in partial tip pickup mode.", # noqa: E501 ) - Flex_P1000_96_TC_2_16_AnalysisError_PartialTipPickupThermocyclerLidConflict: Protocol = Protocol( - file_name="Flex_P1000_96_TC_2_16_AnalysisError_PartialTipPickupThermocyclerLidConflict", + Flex_X_v2_16_P1000_96_TC_PartialTipPickupThermocyclerLidConflict: Protocol = Protocol( + file_stem="Flex_X_v2_16_P1000_96_TC_PartialTipPickupThermocyclerLidConflict", file_extension="py", - protocol_name="Partial Tip Pickup Thermocycler Lid Conflict", robot="Flex", app_error=True, robot_error=False, app_analysis_error="IncompatibleAddressableAreaError [line 15]: Cannot use Slot C3, not compatible with one or more of the following fixtures: Thermocycler in C3", # noqa: E501 ) - Flex_P1000_96_Gripper_2_16_TriggerPrepareForMountMovement: Protocol = Protocol( - file_name="Flex_P1000_96_Gripper_2_16_TriggerPrepareForMountMovement", + Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_TriggerPrepareForMountMovement: Protocol = Protocol( + file_stem="Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_TriggerPrepareForMountMovement", file_extension="py", - protocol_name="96ch protocol with modules gripper moves and pipette aspirations", robot="Flex", app_error=False, robot_error=False, ) + + Flex_S_v2_18_NO_PIPETTES_GoldenRTP: Protocol = Protocol( + file_stem="Flex_S_v2_18_NO_PIPETTES_GoldenRTP", + file_extension="py", + robot="Flex", + app_error=False, + robot_error=False, + ) + + Flex_X_v2_18_NO_PIPETTES_DescriptionTooLongRTP: Protocol = Protocol( + file_stem="Flex_X_v2_18_NO_PIPETTES_DescriptionTooLongRTP", + file_extension="py", + robot="Flex", + app_error=True, + robot_error=True, + ) + + OT2_X_v2_18_None_None_duplicateRTPVariableName: Protocol = Protocol( + file_stem="OT2_X_v2_18_None_None_duplicateRTPVariableName", + file_extension="py", + robot="OT2", + app_error=True, + robot_error=True, + ) + + OT2_S_v2_18_None_None_duplicateChoiceValue: Protocol = Protocol( + file_stem="OT2_S_v2_18_None_None_duplicateChoiceValue", + file_extension="py", + robot="OT2", + app_error=False, + robot_error=False, + ) + + OT2_X_v2_18_None_None_StrRTPwith_unit: Protocol = Protocol( + file_stem="OT2_X_v2_18_None_None_StrRTPwith_unit", + file_extension="py", + robot="OT2", + app_error=True, + robot_error=True, + ) + + OT2_X_v2_18_None_None_NoRTPdisplay_name: Protocol = Protocol( + file_stem="OT2_X_v2_18_None_None_NoRTPdisplay_name", + file_extension="py", + robot="OT2", + app_error=True, + robot_error=True, + ) + + OT2_S_v2_18_NO_PIPETTES_GoldenRTP_OT2: Protocol = Protocol( + file_stem="OT2_S_v2_18_NO_PIPETTES_GoldenRTP_OT2", + file_extension="py", + robot="OT2", + app_error=False, + robot_error=False, + ) diff --git a/app-testing/automation/data/protocols_with_overrides.py b/app-testing/automation/data/protocols_with_overrides.py new file mode 100644 index 00000000000..2c6133180ad --- /dev/null +++ b/app-testing/automation/data/protocols_with_overrides.py @@ -0,0 +1,46 @@ +from automation.data.protocol_with_overrides import ProtocolWithOverrides + + +class ProtocolsWithOverrides: + Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP: ProtocolWithOverrides = ProtocolWithOverrides( + file_stem="Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP", + file_extension="py", + robot="Flex", + app_error=True, + robot_error=True, + override_variable_name="type_to_test", + overrides=[ + "wrong_type_in_display_name", + "wrong_type_in_variable_name", + "wrong_type_in_choice_display_name", + "wrong_type_in_choice_value", + "wrong_type_in_default", + "wrong_type_in_description", + "wrong_type_in_minimum", + "wrong_type_in_maximum", + "wrong_type_in_unit", # we going unit or suffix? + ], + ) + + Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultOutOfRangeRTP: ProtocolWithOverrides = ProtocolWithOverrides( + file_stem="Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultOutOfRangeRTP", + file_extension="py", + robot="Flex", + app_error=True, + robot_error=True, + override_variable_name="type_to_test", + overrides=[ + "default_greater_than_maximum", + "default_less_than_minimum", + ], + ) + + Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultChoiceNoMatchChoice: ProtocolWithOverrides = ProtocolWithOverrides( + file_stem="Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultChoiceNoMatchChoice", + file_extension="py", + robot="Flex", + app_error=True, + robot_error=True, + override_variable_name="type_to_test", + overrides=["str_default_no_matching_choices", "float_default_no_matching_choices", "int_default_no_matching_choices"], + ) diff --git a/app-testing/automation/driver/base.py b/app-testing/automation/driver/base.py index 7ff6e5f39af..3ec9317b835 100644 --- a/app-testing/automation/driver/base.py +++ b/app-testing/automation/driver/base.py @@ -2,6 +2,7 @@ Expose clear information upon failure. """ + from __future__ import annotations import os diff --git a/app-testing/automation/driver/drag_drop.py b/app-testing/automation/driver/drag_drop.py index 0605be6e02e..90d24748a4a 100644 --- a/app-testing/automation/driver/drag_drop.py +++ b/app-testing/automation/driver/drag_drop.py @@ -1,4 +1,5 @@ """Inject javascript to utilize drag and drop functionality.""" + from pathlib import Path from selenium.webdriver.chrome.webdriver import WebDriver diff --git a/app-testing/automation/driver/wait.py b/app-testing/automation/driver/wait.py index 90274d43d21..5213239df3b 100644 --- a/app-testing/automation/driver/wait.py +++ b/app-testing/automation/driver/wait.py @@ -2,6 +2,7 @@ https://stackoverflow.com/questions/2785821/is-there-an-easy-way-in-python-to-wait-until-certain-condition-is-true """ + import time from typing import Any, Callable, Optional diff --git a/app-testing/automation/menus/left_menu.py b/app-testing/automation/menus/left_menu.py index 1875bc0fa12..a567a38a6f6 100644 --- a/app-testing/automation/menus/left_menu.py +++ b/app-testing/automation/menus/left_menu.py @@ -1,4 +1,5 @@ """Left Menu Locators.""" + from typing import Literal from rich.console import Console diff --git a/app-testing/automation/pages/app_settings.py b/app-testing/automation/pages/app_settings.py index d5480a1678d..fc734321ba4 100644 --- a/app-testing/automation/pages/app_settings.py +++ b/app-testing/automation/pages/app_settings.py @@ -1,4 +1,5 @@ """Model for the App Settings page that displays info and settings for the app.""" + from typing import Optional from rich.console import Console diff --git a/app-testing/automation/pages/deck_calibrate.py b/app-testing/automation/pages/deck_calibrate.py index f2b6aa5eeb4..fc5941ec89c 100644 --- a/app-testing/automation/pages/deck_calibrate.py +++ b/app-testing/automation/pages/deck_calibrate.py @@ -1,4 +1,5 @@ """Model for the screens of deck calibration.""" + from enum import Enum from typing import Optional diff --git a/app-testing/automation/pages/device_landing.py b/app-testing/automation/pages/device_landing.py index b2d32885fbf..3cb6dc9a570 100644 --- a/app-testing/automation/pages/device_landing.py +++ b/app-testing/automation/pages/device_landing.py @@ -1,4 +1,5 @@ """Model for the App page that displays info and settings for the app.""" + import time from typing import List, Optional diff --git a/app-testing/automation/pages/labware_landing.py b/app-testing/automation/pages/labware_landing.py index b3ef87940d9..2ed609f2881 100644 --- a/app-testing/automation/pages/labware_landing.py +++ b/app-testing/automation/pages/labware_landing.py @@ -1,4 +1,5 @@ """Model for the Labware Landing page that displays labware info for the app.""" + from typing import Optional from rich.console import Console diff --git a/app-testing/automation/pages/labware_setup.py b/app-testing/automation/pages/labware_setup.py index 514a8916716..818a41a3518 100644 --- a/app-testing/automation/pages/labware_setup.py +++ b/app-testing/automation/pages/labware_setup.py @@ -1,4 +1,5 @@ """Model for the screen of Labware Setup.""" + from rich.console import Console from selenium.webdriver.chrome.webdriver import WebDriver from selenium.webdriver.common.action_chains import ActionChains diff --git a/app-testing/automation/pages/modal.py b/app-testing/automation/pages/modal.py index ea4bd67cb64..8cdcf9811a4 100644 --- a/app-testing/automation/pages/modal.py +++ b/app-testing/automation/pages/modal.py @@ -1,4 +1,5 @@ """Model for the App page that displays info and settings for the app.""" + from typing import Optional from rich.console import Console diff --git a/app-testing/automation/pages/module_setup.py b/app-testing/automation/pages/module_setup.py index 20b024b807f..7c7656bc710 100644 --- a/app-testing/automation/pages/module_setup.py +++ b/app-testing/automation/pages/module_setup.py @@ -1,6 +1,5 @@ """Model for the screen of module setup.""" - from rich.console import Console from selenium.webdriver.chrome.webdriver import WebDriver from selenium.webdriver.common.action_chains import ActionChains diff --git a/app-testing/automation/resources/ot_robot.py b/app-testing/automation/resources/ot_robot.py index a132e19cdcb..2a7e7587140 100644 --- a/app-testing/automation/resources/ot_robot.py +++ b/app-testing/automation/resources/ot_robot.py @@ -1,4 +1,5 @@ """Model the the Opentrons Robot.""" + from typing import List import requests diff --git a/app-testing/automation/resources/robot_data.py b/app-testing/automation/resources/robot_data.py index b248029bcf2..c84f9735a12 100644 --- a/app-testing/automation/resources/robot_data.py +++ b/app-testing/automation/resources/robot_data.py @@ -1,4 +1,5 @@ """Robot data.""" + from dataclasses import dataclass from typing import Literal diff --git a/app-testing/citools/Dockerfile b/app-testing/citools/Dockerfile index 05b2ed538ff..71522ec11b2 100644 --- a/app-testing/citools/Dockerfile +++ b/app-testing/citools/Dockerfile @@ -13,6 +13,7 @@ ARG OPENTRONS_VERSION=edge WORKDIR /opentrons # Clone the Opentrons repository at the specified commit or tag +ARG CACHEBUST=1 RUN git clone --branch $OPENTRONS_VERSION --depth 1 https://github.com/Opentrons/opentrons . # Install packages from local directories diff --git a/app-testing/citools/generate_analyses.py b/app-testing/citools/generate_analyses.py index c8bccc9af45..67ad42c44c7 100644 --- a/app-testing/citools/generate_analyses.py +++ b/app-testing/citools/generate_analyses.py @@ -1,23 +1,17 @@ -# docker build --build-arg OPENTRONS_VERSION=v7.0.2 -t opentrons-analysis:v7.0.2 . -# docker build --build-arg OPENTRONS_VERSION=v7.1.0-alpha.1 -t opentrons-analysis:v7.1.0-alpha.1 . -# docker build --build-arg OPENTRONS_VERSION=v7.1.0-alpha.2 -t opentrons-analysis:v7.1.0-alpha.2 . -# docker build --build-arg OPENTRONS_VERSION=v7.1.0-alpha.3 -t opentrons-analysis:v7.1.0-alpha.3 . - -# python -m pipenv run python citools/generate_analyses.py - import json import os +import signal import time +from contextlib import contextmanager from dataclasses import dataclass +from datetime import datetime, timezone from enum import Enum, auto from pathlib import Path -from typing import Any, Dict, List +from typing import Any, Dict, Generator, List, Optional import docker # type: ignore from automation.data.protocol import Protocol -from rich import print from rich.console import Console -from rich.panel import Panel from rich.traceback import install install(show_locals=True) @@ -33,31 +27,76 @@ console = Console() +@contextmanager +def timeout(seconds: int) -> Generator[None, None, None]: + # Signal handler function + def raise_timeout(signum, frame) -> None: # type: ignore[no-untyped-def] + raise TimeoutError + + # Set the signal handler for the alarm signal + signal.signal(signal.SIGALRM, raise_timeout) + signal.alarm(seconds) # Set the alarm + try: + yield + finally: + signal.alarm(0) # Disable the alarm + + class ProtocolType(Enum): PROTOCOL_DESIGNER = auto() PYTHON = auto() @dataclass -class AnalyzeProtocol: +class AnalyzedProtocol: host_protocol_file: Path container_protocol_file: Path host_analysis_file: Path container_analysis_file: Path tag: str - analysis_execution_time: float | None = None - exit_code: int | None = None - output: str | None = None - analysis: Dict[str, Any] | None = None + analysis_execution_time: Optional[float] = None + command_exit_code: Optional[int] = None + command_output: Optional[str] = None + analysis: Optional[Dict[str, Any]] = None @property def analysis_file_exists(self) -> bool: return self.host_analysis_file.exists() + def create_failed_analysis(self) -> Dict[str, Any]: + created_at = datetime.now(timezone.utc).isoformat() + + return { + "createdAt": created_at, + "errors": [ + { + "analysis_execution_time": self.analysis_execution_time, + "command_output": self.command_output, + "command_exit_code": self.command_exit_code, + }, + ], + "files": [], + "metadata": [], + "commands": [], + "labware": [], + "pipettes": [], + "modules": [], + "liquids": [], + "config": {}, + "runTimeParameters": [], + } + + def write_failed_analysis(self) -> None: + analysis = self.create_failed_analysis() + with open(self.host_analysis_file, "w") as file: + json.dump(analysis, file, indent=4) + def set_analysis(self) -> None: if self.analysis_file_exists: with open(self.host_analysis_file, "r") as file: self.analysis = json.load(file) + else: + self.write_failed_analysis() @property def protocol_file_name(self) -> str: @@ -71,7 +110,7 @@ def set_analysis_execution_time(self, analysis_execution_time: float) -> None: self.analysis_execution_time = analysis_execution_time -def run_container(image_name: str, timeout: int = 60) -> docker.models.containers.Container: +def stop_and_restart_container(image_name: str, timeout: int = 60) -> docker.models.containers.Container: client = docker.from_env() volumes = { str(HOST_LABWARE): {"bind": CONTAINER_LABWARE, "mode": "rw"}, @@ -79,30 +118,30 @@ def run_container(image_name: str, timeout: int = 60) -> docker.models.container str(HOST_PROTOCOLS_ROOT): {"bind": CONTAINER_PROTOCOLS_ROOT, "mode": "rw"}, } - # Check for running containers using the specified image + # Find the running container using the specified image containers = client.containers.list(filters={"ancestor": image_name, "status": "running"}) if containers: - print("Container already running.") - print("Exiting, stop this container so that you may be sure to have the right volumes attached.") - exit(1) - else: - # If no running container is found, start a new one with the specified volume - print("Starting a new container.") - container = client.containers.run(image_name, detach=True, volumes=volumes) + console.print("Stopping the running container(s)...") + for container in containers: + container.stop(timeout=10) + + # Start a new container with the specified volume + console.print("Starting a new container.") + container = client.containers.run(image_name, detach=True, volumes=volumes) # Wait for the container to be ready if a readiness command is provided start_time = time.time() while time.time() - start_time < timeout: exit_code, output = container.exec_run(f"ls -al {CONTAINER_LABWARE}") if exit_code == 0: - print("Container is ready.") + console.print("Container is ready.") break else: - print("Waiting for container to be ready...") + console.print("Waiting for container to be ready...") time.sleep(5) else: - print("Timeout waiting for container to be ready. Proceeding anyway.") + console.print("Timeout waiting for container to be ready. Proceeding anyway.") return container @@ -116,14 +155,14 @@ def stop_and_remove_containers(image_name: str) -> None: try: # Stop the container if it's running if container.status == "running": - print(f"Stopping container {container.short_id}...") - container.stop() + console.print(f"Stopping container {container.short_id}...") + container.stop(timeout=10) # Remove the container - print(f"Removing container {container.short_id}...") + console.print(f"Removing container {container.short_id}...") container.remove() except docker.errors.ContainerError as e: - print(f"Error stopping/removing container {container.short_id}: {e}") + console.print(f"Error stopping/removing container {container.short_id}: {e}") def has_designer_application(json_file_path: Path) -> bool: @@ -133,7 +172,7 @@ def has_designer_application(json_file_path: Path) -> bool: return "designerApplication" in data except json.JSONDecodeError: # Handle the exception if the file is not a valid JSON - print(f"Invalid JSON file: {json_file_path}") + console.print(f"Invalid JSON file: {json_file_path}") return False @@ -145,8 +184,8 @@ def container_analysis_path(protocol_file: Path, tag: str) -> Path: return Path(CONTAINER_RESULTS, f"{protocol_file.stem}_{tag}_{ANALYSIS_SUFFIX}") -def generate_protocols(tag: str) -> List[AnalyzeProtocol]: - def find_pd_protocols() -> List[AnalyzeProtocol]: +def generate_protocols(tag: str) -> List[AnalyzedProtocol]: + def find_pd_protocols() -> List[AnalyzedProtocol]: # Check if the provided path is a valid directory if not HOST_PROTOCOLS_ROOT.is_dir(): raise NotADirectoryError(f"The path {HOST_PROTOCOLS_ROOT} is not a valid directory.") @@ -154,27 +193,29 @@ def find_pd_protocols() -> List[AnalyzeProtocol]: # Recursively find all .json files json_files = list(HOST_PROTOCOLS_ROOT.rglob("*.json")) filtered_json_files = [file for file in json_files if has_designer_application(file)] - pd_protocols: List[AnalyzeProtocol] = [] + pd_protocols: List[AnalyzedProtocol] = [] for path in filtered_json_files: relative_path = path.relative_to(HOST_PROTOCOLS_ROOT) updated_path = Path(CONTAINER_PROTOCOLS_ROOT, relative_path) - pd_protocols.append(AnalyzeProtocol(path, updated_path, host_analysis_path(path, tag), container_analysis_path(path, tag), tag)) + pd_protocols.append( + AnalyzedProtocol(path, updated_path, host_analysis_path(path, tag), container_analysis_path(path, tag), tag) + ) return pd_protocols - def find_python_protocols() -> List[AnalyzeProtocol]: + def find_python_protocols() -> List[AnalyzedProtocol]: # Check if the provided path is a valid directory if not HOST_PROTOCOLS_ROOT.is_dir(): raise NotADirectoryError(f"The path {HOST_PROTOCOLS_ROOT} is not a valid directory.") # Recursively find all .py files python_files = list(HOST_PROTOCOLS_ROOT.rglob("*.py")) - py_protocols: List[AnalyzeProtocol] = [] + py_protocols: List[AnalyzedProtocol] = [] for path in python_files: relative_path = path.relative_to(HOST_PROTOCOLS_ROOT) container_path = Path(CONTAINER_PROTOCOLS_ROOT, relative_path) py_protocols.append( - AnalyzeProtocol(path, container_path, host_analysis_path(path, tag), container_analysis_path(path, tag), tag=tag) + AnalyzedProtocol(path, container_path, host_analysis_path(path, tag), container_analysis_path(path, tag), tag=tag) ) return py_protocols @@ -190,24 +231,7 @@ def remove_all_files_in_directory(directory: Path) -> None: elif os.path.isdir(file_path): pass # Currently, subdirectories are not removed except Exception as e: - print(f"Failed to delete {file_path}. Reason: {e}") - - -def report(protocol: AnalyzeProtocol) -> None: - panel = Panel( - f"[bold green]Output:[/bold green]\n{protocol.output}\n\n[bold red]Exit Code:[/bold red] {protocol.exit_code}", - title="[bold magenta]Command Result[/bold magenta]", - expand=False, - ) - console.print(panel) - if protocol.analysis_file_exists is True: - if protocol.analysis is not None and protocol.analysis["errors"] != []: - console.print(f"[bold red]Analysis has errors {protocol.protocol_file_name}[/bold red]") - console.print(protocol.analysis["errors"]) - console.print(protocol.output) - else: - console.print(f"[bold red]Analysis not created for {protocol.protocol_file_name}[/bold red]") - console.print(protocol.output) + console.print(f"Failed to delete {file_path}. Reason: {e}") def container_custom_labware_paths() -> List[str]: @@ -216,32 +240,59 @@ def container_custom_labware_paths() -> List[str]: return [] -def analyze(protocol: AnalyzeProtocol, container: docker.models.containers.Container) -> None: +def analyze(protocol: AnalyzedProtocol, container: docker.models.containers.Container) -> bool: # Run the analyze command command = f"python -I -m opentrons.cli analyze --json-output {protocol.container_analysis_file} {protocol.container_protocol_file} {' '.join(map(str, container_custom_labware_paths()))}" # noqa: E501 start_time = time.time() - exit_code, result = container.exec_run(command) # Assuming container is a defined object - protocol.output = result.decode("utf-8") - protocol.exit_code = exit_code - protocol.set_analysis() + timeout_duration = 30 # seconds + try: + with timeout(timeout_duration): + command_result = container.exec_run(cmd=command) + exit_code = command_result.exit_code + result = command_result.output + protocol.command_output = result.decode("utf-8") + protocol.command_exit_code = exit_code + protocol.set_analysis() + protocol.set_analysis_execution_time(time.time() - start_time) + return True + except TimeoutError: + console.print(f"Command execution exceeded {timeout_duration} seconds and was aborted.") + logs = container.logs() + # Decode and print the logs + console.print(f"container logs{logs.decode('utf-8')}") + except KeyboardInterrupt: + console.print("Execution was interrupted by the user.") + raise + except Exception as e: + console.print(f"An unexpected error occurred: {e}") + protocol.command_output = result.decode("utf-8") + console.print(f"Command output: {protocol.command_output}") + protocol.command_exit_code = exit_code + console.print(f"Exit code: {protocol.command_exit_code}") + protocol.set_analysis() + return False + protocol.command_output = None + protocol.command_exit_code = None + protocol.analysis = None protocol.set_analysis_execution_time(time.time() - start_time) + return False -def analyze_many(protocol_files: List[AnalyzeProtocol], container: docker.models.containers.Container) -> None: +def analyze_many(protocol_files: List[AnalyzedProtocol], container: docker.models.containers.Container) -> None: for file in protocol_files: analyze(file, container) accumulated_time = sum(protocol.analysis_execution_time for protocol in protocol_files if protocol.analysis_execution_time is not None) console.print(f"{len(protocol_files)} protocols with total analysis time of {accumulated_time:.2f} seconds.\n") -def analyze_against_image(tag: str) -> List[AnalyzeProtocol]: +def analyze_against_image(tag: str) -> List[AnalyzedProtocol]: image_name = f"{IMAGE}:{tag}" protocols = generate_protocols(tag) protocols_to_process = protocols # protocols_to_process = protocols[:1] # For testing try: console.print(f"Analyzing {len(protocols_to_process)} protocol(s) against {image_name}...") - container = run_container(image_name) + container = stop_and_restart_container(image_name) analyze_many(protocols_to_process, container) finally: stop_and_remove_containers(image_name) @@ -250,19 +301,30 @@ def analyze_against_image(tag: str) -> List[AnalyzeProtocol]: def generate_analyses_from_test(tag: str, protocols: List[Protocol]) -> None: """Generate analyses from the tests.""" - image_name = f"{IMAGE}:{tag}" - protocols_to_process: List[AnalyzeProtocol] = [] - for protocol in protocols: - host_protocol_file = Path(protocol.file_path) - container_protocol_file = Path(CONTAINER_PROTOCOLS_ROOT, host_protocol_file.relative_to(HOST_PROTOCOLS_ROOT)) - host_analysis_file = host_analysis_path(host_protocol_file, tag) - container_analysis_file = container_analysis_path(host_protocol_file, tag) - protocols_to_process.append( - AnalyzeProtocol(host_protocol_file, container_protocol_file, host_analysis_file, container_analysis_file, tag) - ) try: + image_name = f"{IMAGE}:{tag}" + protocols_to_process: List[AnalyzedProtocol] = [] + # convert the protocols to AnalyzedProtocol + for test_protocol in protocols: + host_protocol_file = Path(test_protocol.file_path) + container_protocol_file = Path(CONTAINER_PROTOCOLS_ROOT, host_protocol_file.relative_to(HOST_PROTOCOLS_ROOT)) + host_analysis_file = host_analysis_path(host_protocol_file, tag) + container_analysis_file = container_analysis_path(host_protocol_file, tag) + protocols_to_process.append( + AnalyzedProtocol(host_protocol_file, container_protocol_file, host_analysis_file, container_analysis_file, tag) + ) console.print(f"Analyzing {len(protocols_to_process)} protocol(s) against {tag}...") - container = run_container(image_name) - analyze_many(protocols_to_process, container) + container = stop_and_restart_container(image_name) + # Analyze the protocols + for protocol_to_analyze in protocols_to_process: + console.print(f"Analyzing {protocol_to_analyze.host_protocol_file}...") + analyzed = analyze(protocol_to_analyze, container) + if not analyzed: # Fail fast + console.print("Analysis failed. Exiting.") + stop_and_remove_containers(image_name) + accumulated_time = sum( + protocol.analysis_execution_time for protocol in protocols_to_process if protocol.analysis_execution_time is not None + ) + console.print(f"{len(protocols_to_process)} protocols with total analysis time of {accumulated_time:.2f} seconds.\n") finally: stop_and_remove_containers(image_name) diff --git a/app-testing/citools/write_failed_analysis.py b/app-testing/citools/write_failed_analysis.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/app-testing/conftest.py b/app-testing/conftest.py index 1c2762fffd4..dc12b965acc 100644 --- a/app-testing/conftest.py +++ b/app-testing/conftest.py @@ -1,4 +1,5 @@ """Pytest setup.""" + import os from typing import Generator, List, Optional @@ -30,21 +31,6 @@ raise AssertionError("No .env or example.env file found.") -def pytest_collection_modifyitems(items): # type: ignore # noqa: ANN201,ANN001 - """Order tests.""" - # When running all tests calibrate the robot first. - # Most other tests require this. - MODULE_ORDER = ["tests.calibrate_test"] - module_mapping = {item: item.module.__name__ for item in items} - sorted_items = items.copy() - # Iteratively move tests of each module to the end of the test queue - for module in MODULE_ORDER: - sorted_items = [it for it in sorted_items if module_mapping[it] == module] + [ - it for it in sorted_items if module_mapping[it] != module - ] - items[:] = sorted_items - - def _chrome_options() -> Options: """Chrome options for setup.""" options = Options() @@ -52,14 +38,14 @@ def _chrome_options() -> Options: assert executable_path is not None, "EXECUTABLE_PATH environment variable must be set" _console.print(f"EXECUTABLE_PATH is {executable_path}", style="white on blue") options.binary_location = executable_path - options.add_argument("whitelisted-ips=''") # type: ignore - options.add_argument("disable-xss-auditor") # type: ignore - options.add_argument("disable-web-security") # type: ignore - options.add_argument("allow-running-insecure-content") # type: ignore - options.add_argument("no-sandbox") # type: ignore - options.add_argument("disable-setuid-sandbox") # type: ignore - options.add_argument("disable-popup-blocking") # type: ignore - options.add_argument("allow-elevated-browser") # type: ignore + options.add_argument("whitelisted-ips=''") + options.add_argument("disable-xss-auditor") + options.add_argument("disable-web-security") + options.add_argument("allow-running-insecure-content") + options.add_argument("no-sandbox") + options.add_argument("disable-setuid-sandbox") + options.add_argument("disable-popup-blocking") + options.add_argument("allow-elevated-browser") return options diff --git a/app-testing/example.env b/app-testing/example.env index 980dc6335d8..749dddc4cf6 100644 --- a/app-testing/example.env +++ b/app-testing/example.env @@ -9,7 +9,7 @@ ROBOT_BASE_URL="http://localhost:31950" # slow down execution and highlight found elements SLOWMO=TrUe HIGHLIGHT_SECONDS=.3 # default is 2 -UPDATE_CHANNEL="beta" # latest beta alpha +UPDATE_CHANNEL="alpha" # latest beta alpha LOCALHOST=false # Analyses Snapshot test target TARGET=edge @@ -18,89 +18,101 @@ TARGET=edge # dynamically generate with make print-protocols APP_ANALYSIS_TEST_PROTOCOLS=" - OT2_P300SLeft_MM1_MM_TM_2_3_Mix, - OT2_P300SLeft_MM1_MM_2_2_EngageMagHeightFromBase, - OT2_P300SLeft_MM_TM_TM_5_2_6_MOAMTemps, - OT2_P300SG1_None_5_2_6_Gen1PipetteSimple, - OT2_P300S_Twinning_Error, - OT2_P300S_Thermocycler_Moam_Error, - OT2_P300MLeft_MM_TM_2_4_Zymo, - OT2_P300M_P300S_HS_6_1_HS_NormalUseWithTransfer, - OT2_P300M_P20S_TC_MM_TM_2_13_Smoke620Release, - OT2_P300M_P20S_TC_HS_TM_2_16_SmokeTestV3, - OT2_P300M_P20S_TC_HS_TM_2_16_aspirateDispenseMix0Volume, - OT2_P300M_P20S_TC_HS_TM_2_15_SmokeTestV3, - OT2_P300M_P20S_TC_HS_TM_2_14_SmokeTestV3, - OT2_P300M_P20S_TC_HS_TM_2_13_SmokeTestV3, - OT2_P300M_P20S_None_2_12_FailOnRun, - OT2_P300M_P20S_NoMod_6_1_MixTransferManyLiquids, - OT2_P300M_P20S_MM_TM_TC1_5_2_6_PD40Error, - OT2_P300M_P20S_MM_TM_TC1_5_2_6_PD40, - OT2_P300M_P20S_MM_HS_TD_TC_6_1_AllMods_Error, - OT2_P300M_P20S_HS_6_1_Smoke620release, - OT2_P300M_P20S_2_16_aspirateDispenseMix0Volume, - OT2_P20SRight_None_6_1_SimpleTransferError, - OT2_P20S_P300M_NoMods_6_1_TransferReTransferLiquid, - OT2_P20S_P300M_HS_6_1_HS_WithCollision_Error, - OT2_P20S_None_2_7_Walkthrough, - OT2_P10S_P300M_TC1_TM_MM_2_11_Swift, - OT2_P1000SLeft_None_6_1_SimpleTransfer, - OT2_None_None_2_13_PythonSyntaxError, - OT2_None_None_2_12_Python310SyntaxRobotAnalysisOnlyError, - Flex_P50MLeft_P1000MRight_None_2_15_ABRKAPALibraryQuantLongv2, - Flex_P300Gen2_None_2_16_AnalysisError_OT2PipetteInFlexProtocol, - Flex_P1000SRight_None_2_15_ABR_Simple_Normalize_Long_Right, - Flex_P1000MLeft_P50MRight_HS_TM_MM_TC_2_15_ABR4_Illumina_DNA_Prep_24x, - Flex_P1000MLeft_P50MRight_HS_MM_TC_TM_2_15_ABR3_Illumina_DNA_Enrichment, - Flex_P1000MLeft_P50MRight_HS_MM_TC_TM_2_15_ABR3_Illumina_DNA_Enrichment_v4, - Flex_P1000_96_TM_2_16_AnalysisError_ModuleAndWasteChuteConflict, - Flex_P1000_96_None_2_15_ABR5_6_IDT_xGen_EZ_96x_Head_PART_I_III_ABR, - Flex_P1000_96_HS_TM_TC_MM_2_15_ABR5_6_Illumina_DNA_Prep_96x_Head_PART_III, - Flex_P1000_96_HS_TM_MM_2_15_MagMaxRNACells96Ch, - Flex_P1000_96_HS_TM_MM_2_15_ABR5_6_HDQ_Bacteria_ParkTips_96_channel, - Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_Smoke, - Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1, - Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoModulesNoFixtures, - Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoModules, - Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoFixtures, - Flex_P1000_96_GRIPPER_2_16_AnalysisError_DropLabwareIntoTrashBin, - Flex_P1000_96_2_16_AnalysisError_DropTipsWithNoTrash, - Flex_P100_96_HS_TM_2_15_Quick_Zymo_RNA_Bacteria, - Flex_None_None_TM_2_16_AnalysisError_ModuleInStagingAreaCol4, - Flex_None_None_TM_2_16_AnalysisError_ModuleInStagingAreaCol3, - Flex_None_None_TM_2_16_AnalysisError_ModuleInCol2, - Flex_None_None_MM_2_16_AnalysisError_MagneticModuleInFlexProtocol, - Flex_None_None_2_16_AnalysisError_TrashBinInStagingAreaCol4, - Flex_None_None_2_16_AnalysisError_TrashBinInStagingAreaCol3, - Flex_None_None_2_16_AnalysisError_TrashBinInCol2, - Flex_None_None_2_16_AnalysisError_AccessToFixedTrashProp, - OT2_P300S_None_2_16_verifyNoFloatingPointErrorInPipetting, - OT2_P300M_P20S_TC_HS_TM_2_17_SmokeTestV3, - OT2_P300M_P20S_TC_HS_TM_2_17_dispense_changes, - OT2_P300M_P20S_TC_HS_TM_2_16_dispense_changes, - OT2_P300M_P20S_TC_HS_TM_2_15_dispense_changes, - OT2_None_None_TC_2_17_VerifyThermocyclerLoadedSlots, - OT2_None_None_TC_2_16_VerifyThermocyclerLoadedSlots, - OT2_None_None_TC_2_15_VerifyThermocyclerLoadedSlots, - OT2_None_None_TC_2_14_VerifyThermocyclerLoadedSlots, - OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin2, - OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin1, - OT2_None_None_2_16_verifyDoesNotDeadlock, - Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLidClips, - Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLid, - Flex_P1000_96_Gripper_TC_TM_HS_AnalysisError_GripperCollisionWithTips, - Flex_None_None_TC_2_17_verifyThermocyclerLoadedSlots, - Flex_None_None_TC_2_16_verifyThermocyclerLoadedSlots, - Flex_None_None_TC_2_16_AnalysisError_TrashBinAndThermocyclerConflict, - Flex_None_None_TC_2_15_verifyThermocyclerLoadedSlots +Flex_S_v2_15_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots, +Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAEnrichment, +Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAEnrichmentv4, +Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAPrep24x, +Flex_S_v2_15_P1000S_None_SimpleNormalizeLongRight, +Flex_S_v2_15_P1000_96_GRIP_HS_MB_TC_TM_IDTXgen96Part1to3, +Flex_S_v2_15_P1000_96_GRIP_HS_MB_TC_TM_IlluminaDNAPrep96PART3, +Flex_S_v2_15_P1000_96_GRIP_HS_MB_TM_MagMaxRNAExtraction, +Flex_S_v2_15_P1000_96_GRIP_HS_MB_TM_OmegaHDQDNAExtraction, +Flex_S_v2_15_P1000_96_GRIP_HS_TM_QuickZymoMagbeadRNAExtraction, +Flex_S_v2_15_P50M_P1000M_KAPALibraryQuantLongv2, +Flex_S_v2_16_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots, +Flex_S_v2_16_P1000_96_GRIP_DeckConfiguration1NoModules, +Flex_S_v2_16_P1000_96_GRIP_DeckConfiguration1NoModulesNoFixtures, +Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_DeckConfiguration1, +Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_DeckConfiguration1NoFixtures, +Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_Smoke, +Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_TriggerPrepareForMountMovement, +Flex_S_v2_16_P1000_96_TC_PartialTipPickupColumn, +Flex_S_v2_16_P1000_96_TC_PartialTipPickupSingle, +Flex_S_v2_17_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots, +Flex_S_v2_18_NO_PIPETTES_GoldenRTP, +Flex_X_v2_16_NO_PIPETTES_AccessToFixedTrashProp, +Flex_X_v2_16_NO_PIPETTES_MM_MagneticModuleInFlexProtocol, +Flex_X_v2_16_NO_PIPETTES_TC_TrashBinAndThermocyclerConflict, +Flex_X_v2_16_NO_PIPETTES_TM_ModuleInCol2, +Flex_X_v2_16_NO_PIPETTES_TM_ModuleInStagingAreaCol3, +Flex_X_v2_16_NO_PIPETTES_TM_ModuleInStagingAreaCol4, +Flex_X_v2_16_NO_PIPETTES_TrashBinInCol2, +Flex_X_v2_16_NO_PIPETTES_TrashBinInStagingAreaCol3, +Flex_X_v2_16_NO_PIPETTES_TrashBinInStagingAreaCol4, +Flex_X_v2_16_P1000_96_DropTipsWithNoTrash, +Flex_X_v2_16_P1000_96_GRIP_DropLabwareIntoTrashBin, +Flex_X_v2_16_P1000_96_TC_PartialTipPickupThermocyclerLidConflict, +Flex_X_v2_16_P1000_96_TC_PartialTipPickupTryToReturnTip, +Flex_X_v2_16_P1000_96_TC_pipetteCollisionWithThermocyclerLid, +Flex_X_v2_16_P1000_96_TC_pipetteCollisionWithThermocyclerLidClips, +Flex_X_v2_16_P1000_96_TM_ModuleAndWasteChuteConflict, +Flex_X_v2_16_P300MGen2_None_OT2PipetteInFlexProtocol, +Flex_X_v2_18_NO_PIPETTES_DescriptionTooLongRTP, +Flex_X_v8_P1000_96_HS_GRIP_TC_TM_GripperCollisionWithTips, +OT2_S_v2_11_P10S_P300M_MM_TC1_TM_Swift, +OT2_S_v2_12_NO_PIPETTES_Python310SyntaxRobotAnalysisOnlyError, +OT2_S_v2_12_P300M_P20S_FailOnRun, +OT2_S_v2_13_P300M_P20S_HS_TC_TM_SmokeTestV3, +OT2_S_v2_13_P300M_P20S_MM_TC_TM_Smoke620Release, +OT2_S_v2_14_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots, +OT2_S_v2_14_P300M_P20S_HS_TC_TM_SmokeTestV3, +OT2_S_v2_15_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots, +OT2_S_v2_15_P300M_P20S_HS_TC_TM_SmokeTestV3, +OT2_S_v2_15_P300M_P20S_HS_TC_TM_dispense_changes, +OT2_S_v2_16_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots, +OT2_S_v2_16_NO_PIPETTES_verifyDoesNotDeadlock, +OT2_S_v2_16_P300M_P20S_HS_TC_TM_SmokeTestV3, +OT2_S_v2_16_P300M_P20S_HS_TC_TM_aspirateDispenseMix0Volume, +OT2_S_v2_16_P300M_P20S_HS_TC_TM_dispense_changes, +OT2_S_v2_16_P300M_P20S_aspirateDispenseMix0Volume, +OT2_S_v2_16_P300S_None_verifyNoFloatingPointErrorInPipetting, +OT2_S_v2_17_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots, +OT2_S_v2_17_P300M_P20S_HS_TC_TM_SmokeTestV3, +OT2_S_v2_17_P300M_P20S_HS_TC_TM_dispense_changes, +OT2_S_v2_18_NO_PIPETTES_GoldenRTP_OT2, +OT2_S_v2_18_None_None_duplicateChoiceValue, +OT2_S_v2_2_P300S_None_MM1_MM2_EngageMagHeightFromBase, +OT2_S_v2_3_P300S_None_MM1_MM2_TM_Mix, +OT2_S_v2_4_P300M_None_MM_TM_Zymo, +OT2_S_v2_7_P20S_None_Walkthrough, +OT2_S_v3_P300SGen1_None_Gen1PipetteSimple, +OT2_S_v4_P300M_P20S_MM_TM_TC1_PD40, +OT2_S_v4_P300S_None_MM_TM_TM_MOAMTemps, +OT2_S_v6_P1000S_None_SimpleTransfer, +OT2_S_v6_P20S_P300M_TransferReTransferLiquid, +OT2_S_v6_P300M_P20S_HS_Smoke620release, +OT2_S_v6_P300M_P20S_MixTransferManyLiquids, +OT2_S_v6_P300M_P300S_HS_HS_NormalUseWithTransfer, +OT2_X_v2_11_P300S_TC1_TC2_ThermocyclerMoamError, +OT2_X_v2_13_None_None_PythonSyntaxError, +OT2_X_v2_16_None_None_HS_HeaterShakerConflictWithTrashBin1, +OT2_X_v2_16_None_None_HS_HeaterShakerConflictWithTrashBin2, +OT2_X_v2_18_None_None_NoRTPdisplay_name, +OT2_X_v2_18_None_None_StrRTPwith_unit, +OT2_X_v2_18_None_None_duplicateRTPVariableName, +OT2_X_v2_7_P300S_TwinningError, +OT2_X_v4_P300M_P20S_MM_TC1_TM_e2eTests, +OT2_X_v6_P20S_None_SimpleTransfer, +OT2_X_v6_P300M_P20S_HS_MM_TM_TC_AllMods +" +APP_ANALYSIS_TEST_PROTOCOLS_WITH_OVERRIDES=" +Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP, +Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultChoiceNoMatchChoice, +Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultOutOfRangeRTP " - -# Not running this file because the error handling to catch that -# the flex is only supported on API versions 2.15 and above, does not exist -# Will be fixed with https://opentrons.atlassian.net/browse/RDEVOPS-71 -# Flex_None_None_TC_2_14_verifyThermocyclerLoadedSlots # run one -# APP_ANALYSIS_TEST_PROTOCOLS="Flex_P1000MLeft_P50MRight_HS_MM_TC_TM_2_15_ABR3_Illumina_DNA_Enrichment" +# APP_ANALYSIS_TEST_PROTOCOLS="Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAEnrichmentv4" +# APP_ANALYSIS_TEST_PROTOCOLS_WITH_OVERRIDES="Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP" FILES_FOLDER="files" diff --git a/app-testing/files/examples/description_too_long_2.18.py b/app-testing/files/examples/description_too_long_2.18.py new file mode 100644 index 00000000000..8b63fe2afd1 --- /dev/null +++ b/app-testing/files/examples/description_too_long_2.18.py @@ -0,0 +1,59 @@ +metadata = { + "protocolName": "Description Too Long 2.18", +} + +requirements = {"robotType": "Flex", "apiLevel": "2.18"} + + +# change me to test that a bad description is caught +# for each type of parameter we can add. +type_to_test = 1 + + +def add_parameters(parameters): + too_long: str = "This is a description that is longer than 30 characters." + match type_to_test: + case 1: + parameters.add_int( + display_name="Dilutions", + variable_name="dilutions", + default=1, + minimum=1, + maximum=3, + description=too_long, + ) + case 2: + parameters.add_float( + display_name="Mixing Volume in µL", + variable_name="mixing_volume", + default=150.0, + choices=[ + {"display_name": "Low Volume ⬇️", "value": 100.0}, + {"display_name": "Medium Volume 🟰", "value": 150.0}, + {"display_name": "High Volume ⬆️", "value": 200.0}, + ], + description=too_long, + ) + case 3: + parameters.add_str( + display_name="Pipette Name", + variable_name="pipette", + choices=[ + {"display_name": "Single channel 50µL", "value": "flex_1channel_50"}, + {"display_name": "Eight Channel 50µL", "value": "flex_8channel_50"}, + ], + default="flex_1channel_50", + description=too_long, + ) + case 4: + parameters.add_bool( + display_name="Dry Run", + variable_name="dry_run", + default=False, + description=too_long, + ) + + +def run(context): + for variable_name, value in context.params.get_all().items(): + context.comment(f"variable {variable_name} has value {value}") diff --git a/app-testing/files/examples/invalid_properties_2.18.py b/app-testing/files/examples/invalid_properties_2.18.py new file mode 100644 index 00000000000..eb8c1d0e745 --- /dev/null +++ b/app-testing/files/examples/invalid_properties_2.18.py @@ -0,0 +1,24 @@ +metadata = { + "protocolName": "Add invalid properties to an RTP", +} + +requirements = {"robotType": "Flex", "apiLevel": "2.18"} + + +def add_parameters(parameters): + parameters.add_int( + display_name="Washes", + variable_name="washes", + default=6, + description="How many washes to perform.", + choices=[ + {"display_name": "1X", "value": 6}, + {"display_name": "2X", "value": 12}, + ], + magic="🪄🪄🪄🪄", + ) + + +def run(context): + for variable_name, value in context.params.get_all().items(): + context.comment(f"variable {variable_name} has value {value}") diff --git a/app-testing/files/examples/invalid_rtp.py b/app-testing/files/examples/invalid_rtp.py new file mode 100644 index 00000000000..5d5fb9d314b --- /dev/null +++ b/app-testing/files/examples/invalid_rtp.py @@ -0,0 +1,78 @@ +from dataclasses import dataclass, fields +from typing import Union + +from typing import Union, Type, List + + +def not_my_type(the_type: Type) -> List[Union[str, float, int, bool, dict, list, tuple, set, frozenset]]: + """ + Returns a list of values of all local variables that do not match the type specified by 'the_type'. + + Args: + the_type: The type (e.g., int, str, list) to be excluded from the return value. + + Returns: + A list of values of local variables not matching 'the_type'. + """ + none: None = None + string: str = "string" + integer: int = 1 + the_float: float = 1.0 + the_dict: dict = {} + the_list: list = [] + the_tuple: tuple = () + the_set: set = set() + the_frozenset: frozenset = frozenset() + + # Collect values that are not of 'the_type'. + return [value for value in locals().values() if not isinstance(value, the_type)] + + +@dataclass +class ErrorVariableNames: + dunder: str = "__dunder" + leading_underscore: str = "_leading_underscore" # maybe + leading_space: str = " space" + trailing_space: str = "space " + middle_space: str = "middle space" + asterisk: str = "*asterisk" + period: str = ".period" + the_def: str = "def" + the_class: str = "class" + the_return: str = "return" + the_yield: str = "yield" + the_raise: str = "raise" + the_except: str = "except" + the_import: str = "import" + the_from: str = "from" + the_as: str = "as" + the_with: str = "with" + the_if: str = "if" + the_else: str = "else" + the_elif: str = "elif" + the_while: str = "while" + the_for: str = "for" + the_in: str = "in" + the_is: str = "is" + the_not: str = "not" + the_and: str = "and" + the_or: str = "or" + the_lambda: str = "lambda" + the_global: str = "global" + the_nonlocal: str = "nonlocal" + the_del: str = "del" + the_pass: str = "pass" + the_break: str = "break" + the_continue: str = "continue" + the_try: str = "try" + the_and: str = "and" + the_none: str = "None" + the_true: str = "True" + the_false: str = "False" + the_as: str = "as" + the_assert: str = "assert" + the_async: str = "async" + the_await: str = "await" + + def get_values(self): + return [getattr(self, field.name) for field in fields(self)] diff --git a/app-testing/files/protocols/py/Flex_None_None_TC_2_15_verifyThermocyclerLoadedSlots.py b/app-testing/files/protocols/Flex_S_v2_15_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots.py similarity index 100% rename from app-testing/files/protocols/py/Flex_None_None_TC_2_15_verifyThermocyclerLoadedSlots.py rename to app-testing/files/protocols/Flex_S_v2_15_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots.py diff --git a/app-testing/files/protocols/py/Flex_P1000MLeft_P50MRight_HS_MM_TC_TM_2_15_ABR3_Illumina_DNA_Enrichment.py b/app-testing/files/protocols/Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAEnrichment.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000MLeft_P50MRight_HS_MM_TC_TM_2_15_ABR3_Illumina_DNA_Enrichment.py rename to app-testing/files/protocols/Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAEnrichment.py diff --git a/app-testing/files/protocols/py/Flex_P1000MLeft_P50MRight_HS_MM_TC_TM_2_15_ABR3_Illumina_DNA_Enrichment_v4.py b/app-testing/files/protocols/Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAEnrichmentv4.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000MLeft_P50MRight_HS_MM_TC_TM_2_15_ABR3_Illumina_DNA_Enrichment_v4.py rename to app-testing/files/protocols/Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAEnrichmentv4.py diff --git a/app-testing/files/protocols/py/Flex_P1000MLeft_P50MRight_HS_TM_MM_TC_2_15_ABR4_Illumina_DNA_Prep_24x.py b/app-testing/files/protocols/Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAPrep24x.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000MLeft_P50MRight_HS_TM_MM_TC_2_15_ABR4_Illumina_DNA_Prep_24x.py rename to app-testing/files/protocols/Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAPrep24x.py diff --git a/app-testing/files/protocols/py/Flex_P1000SRight_None_2_15_ABR_Simple_Normalize_Long_Right.py b/app-testing/files/protocols/Flex_S_v2_15_P1000S_None_SimpleNormalizeLongRight.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000SRight_None_2_15_ABR_Simple_Normalize_Long_Right.py rename to app-testing/files/protocols/Flex_S_v2_15_P1000S_None_SimpleNormalizeLongRight.py diff --git a/app-testing/files/protocols/py/Flex_P1000_96_None_2_15_ABR5_6_IDT_xGen_EZ_96x_Head_PART_I_III_ABR.py b/app-testing/files/protocols/Flex_S_v2_15_P1000_96_GRIP_HS_MB_TC_TM_IDTXgen96Part1to3.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000_96_None_2_15_ABR5_6_IDT_xGen_EZ_96x_Head_PART_I_III_ABR.py rename to app-testing/files/protocols/Flex_S_v2_15_P1000_96_GRIP_HS_MB_TC_TM_IDTXgen96Part1to3.py diff --git a/app-testing/files/protocols/py/Flex_P1000_96_HS_TM_TC_MM_2_15_ABR5_6_Illumina_DNA_Prep_96x_Head_PART_III.py b/app-testing/files/protocols/Flex_S_v2_15_P1000_96_GRIP_HS_MB_TC_TM_IlluminaDNAPrep96PART3.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000_96_HS_TM_TC_MM_2_15_ABR5_6_Illumina_DNA_Prep_96x_Head_PART_III.py rename to app-testing/files/protocols/Flex_S_v2_15_P1000_96_GRIP_HS_MB_TC_TM_IlluminaDNAPrep96PART3.py diff --git a/app-testing/files/protocols/py/Flex_P1000_96_HS_TM_MM_2_15_MagMaxRNACells96Ch.py b/app-testing/files/protocols/Flex_S_v2_15_P1000_96_GRIP_HS_MB_TM_MagMaxRNAExtraction.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000_96_HS_TM_MM_2_15_MagMaxRNACells96Ch.py rename to app-testing/files/protocols/Flex_S_v2_15_P1000_96_GRIP_HS_MB_TM_MagMaxRNAExtraction.py diff --git a/app-testing/files/protocols/py/Flex_P1000_96_HS_TM_MM_2_15_ABR5_6_HDQ_Bacteria_ParkTips_96_channel.py b/app-testing/files/protocols/Flex_S_v2_15_P1000_96_GRIP_HS_MB_TM_OmegaHDQDNAExtraction.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000_96_HS_TM_MM_2_15_ABR5_6_HDQ_Bacteria_ParkTips_96_channel.py rename to app-testing/files/protocols/Flex_S_v2_15_P1000_96_GRIP_HS_MB_TM_OmegaHDQDNAExtraction.py diff --git a/app-testing/files/protocols/py/Flex_P100_96_HS_TM_2_15_Quick_Zymo_RNA_Bacteria.py b/app-testing/files/protocols/Flex_S_v2_15_P1000_96_GRIP_HS_TM_QuickZymoMagbeadRNAExtraction.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P100_96_HS_TM_2_15_Quick_Zymo_RNA_Bacteria.py rename to app-testing/files/protocols/Flex_S_v2_15_P1000_96_GRIP_HS_TM_QuickZymoMagbeadRNAExtraction.py diff --git a/app-testing/files/protocols/py/Flex_P50MLeft_P1000MRight_None_2_15_ABRKAPALibraryQuantLongv2.py b/app-testing/files/protocols/Flex_S_v2_15_P50M_P1000M_KAPALibraryQuantLongv2.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P50MLeft_P1000MRight_None_2_15_ABRKAPALibraryQuantLongv2.py rename to app-testing/files/protocols/Flex_S_v2_15_P50M_P1000M_KAPALibraryQuantLongv2.py diff --git a/app-testing/files/protocols/py/Flex_None_None_TC_2_16_verifyThermocyclerLoadedSlots.py b/app-testing/files/protocols/Flex_S_v2_16_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots.py similarity index 100% rename from app-testing/files/protocols/py/Flex_None_None_TC_2_16_verifyThermocyclerLoadedSlots.py rename to app-testing/files/protocols/Flex_S_v2_16_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots.py diff --git a/app-testing/files/protocols/py/Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoModules.py b/app-testing/files/protocols/Flex_S_v2_16_P1000_96_GRIP_DeckConfiguration1NoModules.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoModules.py rename to app-testing/files/protocols/Flex_S_v2_16_P1000_96_GRIP_DeckConfiguration1NoModules.py diff --git a/app-testing/files/protocols/py/Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoModulesNoFixtures.py b/app-testing/files/protocols/Flex_S_v2_16_P1000_96_GRIP_DeckConfiguration1NoModulesNoFixtures.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoModulesNoFixtures.py rename to app-testing/files/protocols/Flex_S_v2_16_P1000_96_GRIP_DeckConfiguration1NoModulesNoFixtures.py diff --git a/app-testing/files/protocols/py/Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1.py b/app-testing/files/protocols/Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_DeckConfiguration1.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1.py rename to app-testing/files/protocols/Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_DeckConfiguration1.py diff --git a/app-testing/files/protocols/py/Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoFixtures.py b/app-testing/files/protocols/Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_DeckConfiguration1NoFixtures.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoFixtures.py rename to app-testing/files/protocols/Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_DeckConfiguration1NoFixtures.py diff --git a/app-testing/files/protocols/py/Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_Smoke.py b/app-testing/files/protocols/Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_Smoke.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_Smoke.py rename to app-testing/files/protocols/Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_Smoke.py diff --git a/app-testing/files/protocols/py/Flex_P1000_96_Gripper_2_16_TriggerPrepareForMountMovement.py b/app-testing/files/protocols/Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_TriggerPrepareForMountMovement.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000_96_Gripper_2_16_TriggerPrepareForMountMovement.py rename to app-testing/files/protocols/Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_TriggerPrepareForMountMovement.py diff --git a/app-testing/files/protocols/py/Flex_P1000_96_TC_2_16_PartialTipPickupColumn.py b/app-testing/files/protocols/Flex_S_v2_16_P1000_96_TC_PartialTipPickupColumn.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000_96_TC_2_16_PartialTipPickupColumn.py rename to app-testing/files/protocols/Flex_S_v2_16_P1000_96_TC_PartialTipPickupColumn.py diff --git a/app-testing/files/protocols/py/Flex_P1000_96_TC_2_16_PartialTipPickupSingle.py b/app-testing/files/protocols/Flex_S_v2_16_P1000_96_TC_PartialTipPickupSingle.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000_96_TC_2_16_PartialTipPickupSingle.py rename to app-testing/files/protocols/Flex_S_v2_16_P1000_96_TC_PartialTipPickupSingle.py diff --git a/app-testing/files/protocols/py/Flex_None_None_TC_2_17_verifyThermocyclerLoadedSlots.py b/app-testing/files/protocols/Flex_S_v2_17_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots.py similarity index 100% rename from app-testing/files/protocols/py/Flex_None_None_TC_2_17_verifyThermocyclerLoadedSlots.py rename to app-testing/files/protocols/Flex_S_v2_17_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots.py diff --git a/app-testing/files/protocols/Flex_S_v2_18_NO_PIPETTES_GoldenRTP.py b/app-testing/files/protocols/Flex_S_v2_18_NO_PIPETTES_GoldenRTP.py new file mode 100644 index 00000000000..0735a73861b --- /dev/null +++ b/app-testing/files/protocols/Flex_S_v2_18_NO_PIPETTES_GoldenRTP.py @@ -0,0 +1,229 @@ +metadata = { + "protocolName": "Golden RTP Examples", +} + +requirements = {"robotType": "Flex", "apiLevel": "2.18"} + +description: str = "Reused description for all parameters." +unit: str = "unit" + +# parameters with choice having non unique values is acceptable and covered in another protocol +# parameters with display_name="" and description="" is acceptable but silly - no good rule possible to protect against that + + +def add_parameters(parameters): + ###################INT##################### + ### int min/max with all fields ### + parameters.add_int( + display_name="int min/max all", + variable_name="min_max_all_fields", + default=6, + minimum=1, + maximum=12, + description=description, + unit=unit, + ) + #### int min/max without unit ### + parameters.add_int( + display_name="int min/max no unit", + variable_name="int_min_max_without_unit", + default=1, + minimum=1, + maximum=3, + description=description, + # unit is missing + ) + #### int min/max without description ### + parameters.add_int( + display_name="int min/max no description", + variable_name="int_min_max_without_description", + default=1, + minimum=1, + maximum=3, + # description is missing + unit=unit, + ) + #### int min/max without unit and description ### + parameters.add_int( + display_name="int min/max no unit,desc", + variable_name="int_min_max_without_unit_and_description", + default=1, + minimum=1, + maximum=3, + # description is missing + # unit is missing + ) + #### int choices with all fields and unique choice values ### + parameters.add_int( + display_name="int choices all", + variable_name="int_choices_all_fields", + description=description, + unit=unit, + default=20, + choices=[ + {"display_name": "20", "value": 20}, + {"display_name": "16", "value": 16}, + ], + ) + #### int choices without unit and unique choice values ### + parameters.add_int( + display_name="int choice no unit", + variable_name="int_choice_no_unit", + default=6, + description=description, + # unit is missing + choices=[ + {"display_name": "1X", "value": 6}, + {"display_name": "2X", "value": 12}, + ], + ) + #### int choices without unit or description and unique choice values ### + parameters.add_int( + display_name="int choice no unit, desc", + variable_name="int_choice_no_unit_desc", + default=10, + # description is missing + # unit is missing + choices=[ + {"display_name": "10X", "value": 10}, + {"display_name": "100X", "value": 100}, + ], + ) + ###################FLOAT##################### + #### float min/max with all fields ### + parameters.add_float( + display_name="float min/max all fields", + variable_name="float_min_max_all_fields", + default=30.0, + minimum=20.0, + maximum=30.0, + description=description, + unit=unit, + ) + #### float min/max without unit ### + parameters.add_float( + display_name="float min/max no unit", + variable_name="float_min_max_no_unit", + default=1.8, + minimum=1.5, + maximum=3.0, + description=description, + # unit is missing + ) + #### float min/max without unit or description ### + parameters.add_float( + display_name="float min/max no unit,desc", + variable_name="float_min_max_no_unit_or_desc", + default=1.8, + minimum=1.5, + maximum=3.0, + # description is missing + # unit is missing + ) + #### float choices with all and unique choice values ### + parameters.add_float( + display_name="float choices all", + variable_name="float_choices_all_fields", + default=20.0, + choices=[ + {"display_name": "Low Volume (10.0µL)", "value": 10.0}, + {"display_name": "Medium Volume (20.0µL)", "value": 20.0}, + {"display_name": "High Volume (50.0µL)", "value": 50.0}, + ], + description=description, + unit=unit, + ) + #### float choices with without unit and unique choice values ### + parameters.add_float( + display_name="float choices no unit", + variable_name="float_choices_no_unit", + default=10.0, + choices=[ + {"display_name": "Low Volume (10.0µL)", "value": 10.0}, + {"display_name": "High Volume (50.0µL)", "value": 50.0}, + ], + description=description, + # unit is missing + ) + #### float choices with without description and unique choice values ### + parameters.add_float( + display_name="float choices no description", + variable_name="float_choices_no_description", + default=20.0, + choices=[ + {"display_name": "Low Volume (10.0µL)", "value": 10.0}, + {"display_name": "Medium Volume (20.0µL)", "value": 20.0}, + {"display_name": "High Volume (50.0µL)", "value": 50.0}, + ], + # description is missing + unit=unit, + ) + #### float choices with without unit or description and unique choice values ### + parameters.add_float( + display_name="float choices no unit,desc", + variable_name="float_choices_no_unit_or_desc", + default=20.0, + choices=[ + {"display_name": "Low Volume (10.0µL)", "value": 10.0}, + {"display_name": "Medium Volume (20.0µL)", "value": 20.0}, + {"display_name": "High Volume (50.0µL)", "value": 50.0}, + ], + # description is missing + # unit is missing + ) + ###################BOOL##################### + parameters.add_bool( + display_name="bool all fields", + variable_name="bool_all_fields", + default=False, + description="When on, skip aspirate and dispense steps.", + ) + parameters.add_bool( + display_name="bool no description", + variable_name="bool_no_desc", + default=False, + # description is missing + ) + ###################STR##################### + #### str all fields and unique choice values ### + parameters.add_str( + display_name="str choices all", + variable_name="str_choices_all_fields", + choices=[ + {"display_name": "Single channel 50µL", "value": "flex_1channel_50"}, + {"display_name": "Eight Channel 50µL", "value": "flex_8channel_50"}, + ], + default="flex_1channel_50", + description="What pipette to use during the protocol.", + ) + #### str all fields and unique choice values ### + parameters.add_str( + display_name="str choices all many", + variable_name="str_choices_all_many_fields", + choices=[ + {"display_name": "A", "value": "A"}, + {"display_name": "B", "value": "B"}, + {"display_name": "C", "value": "C"}, + {"display_name": "D", "value": "D"}, + {"display_name": "E", "value": "E"}, + {"display_name": "F", "value": "F"}, + ], + default="E", + description=description, + ) + #### str no description and unique choice values ### + parameters.add_str( + display_name="str choices no desc", + variable_name="str_choices_no_desc", + choices=[ + {"display_name": "Single channel 50µL", "value": "flex_1channel_50"}, + {"display_name": "Eight Channel 50µL", "value": "flex_8channel_50"}, + ], + default="flex_1channel_50", + # description is missing + ) + + +def run(context): + for variable_name, value in context.params.get_all().items(): + context.comment(f"variable {variable_name} has value {value}") diff --git a/app-testing/files/protocols/py/Flex_None_None_2_16_AnalysisError_AccessToFixedTrashProp.py b/app-testing/files/protocols/Flex_X_v2_16_NO_PIPETTES_AccessToFixedTrashProp.py similarity index 100% rename from app-testing/files/protocols/py/Flex_None_None_2_16_AnalysisError_AccessToFixedTrashProp.py rename to app-testing/files/protocols/Flex_X_v2_16_NO_PIPETTES_AccessToFixedTrashProp.py diff --git a/app-testing/files/protocols/py/Flex_None_None_MM_2_16_AnalysisError_MagneticModuleInFlexProtocol.py b/app-testing/files/protocols/Flex_X_v2_16_NO_PIPETTES_MM_MagneticModuleInFlexProtocol.py similarity index 100% rename from app-testing/files/protocols/py/Flex_None_None_MM_2_16_AnalysisError_MagneticModuleInFlexProtocol.py rename to app-testing/files/protocols/Flex_X_v2_16_NO_PIPETTES_MM_MagneticModuleInFlexProtocol.py diff --git a/app-testing/files/protocols/py/Flex_None_None_TC_2_16_AnalysisError_TrashBinAndThermocyclerConflict.py b/app-testing/files/protocols/Flex_X_v2_16_NO_PIPETTES_TC_TrashBinAndThermocyclerConflict.py similarity index 100% rename from app-testing/files/protocols/py/Flex_None_None_TC_2_16_AnalysisError_TrashBinAndThermocyclerConflict.py rename to app-testing/files/protocols/Flex_X_v2_16_NO_PIPETTES_TC_TrashBinAndThermocyclerConflict.py diff --git a/app-testing/files/protocols/py/Flex_None_None_TM_2_16_AnalysisError_ModuleInCol2.py b/app-testing/files/protocols/Flex_X_v2_16_NO_PIPETTES_TM_ModuleInCol2.py similarity index 100% rename from app-testing/files/protocols/py/Flex_None_None_TM_2_16_AnalysisError_ModuleInCol2.py rename to app-testing/files/protocols/Flex_X_v2_16_NO_PIPETTES_TM_ModuleInCol2.py diff --git a/app-testing/files/protocols/py/Flex_None_None_TM_2_16_AnalysisError_ModuleInStagingAreaCol3.py b/app-testing/files/protocols/Flex_X_v2_16_NO_PIPETTES_TM_ModuleInStagingAreaCol3.py similarity index 100% rename from app-testing/files/protocols/py/Flex_None_None_TM_2_16_AnalysisError_ModuleInStagingAreaCol3.py rename to app-testing/files/protocols/Flex_X_v2_16_NO_PIPETTES_TM_ModuleInStagingAreaCol3.py diff --git a/app-testing/files/protocols/py/Flex_None_None_TM_2_16_AnalysisError_ModuleInStagingAreaCol4.py b/app-testing/files/protocols/Flex_X_v2_16_NO_PIPETTES_TM_ModuleInStagingAreaCol4.py similarity index 100% rename from app-testing/files/protocols/py/Flex_None_None_TM_2_16_AnalysisError_ModuleInStagingAreaCol4.py rename to app-testing/files/protocols/Flex_X_v2_16_NO_PIPETTES_TM_ModuleInStagingAreaCol4.py diff --git a/app-testing/files/protocols/py/Flex_None_None_2_16_AnalysisError_TrashBinInCol2.py b/app-testing/files/protocols/Flex_X_v2_16_NO_PIPETTES_TrashBinInCol2.py similarity index 100% rename from app-testing/files/protocols/py/Flex_None_None_2_16_AnalysisError_TrashBinInCol2.py rename to app-testing/files/protocols/Flex_X_v2_16_NO_PIPETTES_TrashBinInCol2.py diff --git a/app-testing/files/protocols/py/Flex_None_None_2_16_AnalysisError_TrashBinInStagingAreaCol3.py b/app-testing/files/protocols/Flex_X_v2_16_NO_PIPETTES_TrashBinInStagingAreaCol3.py similarity index 100% rename from app-testing/files/protocols/py/Flex_None_None_2_16_AnalysisError_TrashBinInStagingAreaCol3.py rename to app-testing/files/protocols/Flex_X_v2_16_NO_PIPETTES_TrashBinInStagingAreaCol3.py diff --git a/app-testing/files/protocols/py/Flex_None_None_2_16_AnalysisError_TrashBinInStagingAreaCol4.py b/app-testing/files/protocols/Flex_X_v2_16_NO_PIPETTES_TrashBinInStagingAreaCol4.py similarity index 100% rename from app-testing/files/protocols/py/Flex_None_None_2_16_AnalysisError_TrashBinInStagingAreaCol4.py rename to app-testing/files/protocols/Flex_X_v2_16_NO_PIPETTES_TrashBinInStagingAreaCol4.py diff --git a/app-testing/files/protocols/py/Flex_P1000_96_2_16_AnalysisError_DropTipsWithNoTrash.py b/app-testing/files/protocols/Flex_X_v2_16_P1000_96_DropTipsWithNoTrash.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000_96_2_16_AnalysisError_DropTipsWithNoTrash.py rename to app-testing/files/protocols/Flex_X_v2_16_P1000_96_DropTipsWithNoTrash.py diff --git a/app-testing/files/protocols/py/Flex_P1000_96_GRIPPER_2_16_AnalysisError_DropLabwareIntoTrashBin.py b/app-testing/files/protocols/Flex_X_v2_16_P1000_96_GRIP_DropLabwareIntoTrashBin.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000_96_GRIPPER_2_16_AnalysisError_DropLabwareIntoTrashBin.py rename to app-testing/files/protocols/Flex_X_v2_16_P1000_96_GRIP_DropLabwareIntoTrashBin.py diff --git a/app-testing/files/protocols/py/Flex_P1000_96_TC_2_16_AnalysisError_PartialTipPickupThermocyclerLidConflict.py b/app-testing/files/protocols/Flex_X_v2_16_P1000_96_TC_PartialTipPickupThermocyclerLidConflict.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000_96_TC_2_16_AnalysisError_PartialTipPickupThermocyclerLidConflict.py rename to app-testing/files/protocols/Flex_X_v2_16_P1000_96_TC_PartialTipPickupThermocyclerLidConflict.py diff --git a/app-testing/files/protocols/py/Flex_P1000_96_TC_2_16_AnalysisError_PartialTipPickupTryToReturnTip.py b/app-testing/files/protocols/Flex_X_v2_16_P1000_96_TC_PartialTipPickupTryToReturnTip.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000_96_TC_2_16_AnalysisError_PartialTipPickupTryToReturnTip.py rename to app-testing/files/protocols/Flex_X_v2_16_P1000_96_TC_PartialTipPickupTryToReturnTip.py diff --git a/app-testing/files/protocols/py/Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLid.py b/app-testing/files/protocols/Flex_X_v2_16_P1000_96_TC_pipetteCollisionWithThermocyclerLid.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLid.py rename to app-testing/files/protocols/Flex_X_v2_16_P1000_96_TC_pipetteCollisionWithThermocyclerLid.py diff --git a/app-testing/files/protocols/py/Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLidClips.py b/app-testing/files/protocols/Flex_X_v2_16_P1000_96_TC_pipetteCollisionWithThermocyclerLidClips.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLidClips.py rename to app-testing/files/protocols/Flex_X_v2_16_P1000_96_TC_pipetteCollisionWithThermocyclerLidClips.py diff --git a/app-testing/files/protocols/py/Flex_P1000_96_TM_2_16_AnalysisError_ModuleAndWasteChuteConflict.py b/app-testing/files/protocols/Flex_X_v2_16_P1000_96_TM_ModuleAndWasteChuteConflict.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P1000_96_TM_2_16_AnalysisError_ModuleAndWasteChuteConflict.py rename to app-testing/files/protocols/Flex_X_v2_16_P1000_96_TM_ModuleAndWasteChuteConflict.py diff --git a/app-testing/files/protocols/py/Flex_P300Gen2_None_2_16_AnalysisError_OT2PipetteInFlexProtocol.py b/app-testing/files/protocols/Flex_X_v2_16_P300MGen2_None_OT2PipetteInFlexProtocol.py similarity index 100% rename from app-testing/files/protocols/py/Flex_P300Gen2_None_2_16_AnalysisError_OT2PipetteInFlexProtocol.py rename to app-testing/files/protocols/Flex_X_v2_16_P300MGen2_None_OT2PipetteInFlexProtocol.py diff --git a/app-testing/files/protocols/Flex_X_v2_18_NO_PIPETTES_DescriptionTooLongRTP.py b/app-testing/files/protocols/Flex_X_v2_18_NO_PIPETTES_DescriptionTooLongRTP.py new file mode 100644 index 00000000000..c2f025af63c --- /dev/null +++ b/app-testing/files/protocols/Flex_X_v2_18_NO_PIPETTES_DescriptionTooLongRTP.py @@ -0,0 +1,23 @@ +metadata = { + "protocolName": "Description too long", +} + +requirements = {"robotType": "Flex", "apiLevel": "2.18"} + +too_long: str = "This is a description that is longer than 30 characters." + + +def add_parameters(parameters): + parameters.add_int( + display_name="display name", + variable_name="dilutions", + default=1, + minimum=1, + maximum=3, + description=too_long, + ) + + +def run(context): + for variable_name, value in context.params.get_all().items(): + context.comment(f"variable {variable_name} has value {value}") diff --git a/app-testing/files/protocols/Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP.py b/app-testing/files/protocols/Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP.py new file mode 100644 index 00000000000..c5d32ce71d0 --- /dev/null +++ b/app-testing/files/protocols/Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP.py @@ -0,0 +1,125 @@ +# I am going to get added to in the test runner +# type_to_test = wrong_type_in_display_name +# protocol.override_variable_name = type_to_test + +metadata = { + "protocolName": "Description Too Long 2.18", +} + +requirements = {"robotType": "Flex", "apiLevel": "2.18"} + + +# change me to test that a bad type is caught +# for each field of parameter. +# protocol.overrides is a list of these strings +wrong_type_in_display_name: str = "wrong_type_in_display_name" +wrong_type_in_variable_name: str = "wrong_type_in_variable_name" +wrong_type_in_choice_display_name: str = "wrong_type_in_choice_display_name" +wrong_type_in_choice_value: str = "wrong_type_in_choice_value" +wrong_type_in_default: str = "wrong_type_in_default" +wrong_type_in_description: str = "wrong_type_in_description" +wrong_type_in_minimum: str = "wrong_type_in_minimum" +wrong_type_in_maximum: str = "wrong_type_in_maximum" +wrong_type_in_unit: str = "wrong_type_in_unit" # we going unit or suffix? + + +def add_parameters(parameters): + match type_to_test: + case str() if type_to_test == wrong_type_in_display_name: + parameters.add_int( + display_name=5, + variable_name="dilutions", + default=1, + minimum=1, + maximum=3, + description="This is a description.", + ) + case str() if type_to_test == wrong_type_in_variable_name: + parameters.add_float( + display_name="Mixing Volume in µL", + variable_name={}, + default=150.0, + choices=[ + {"display_name": "Low Volume ⬇️", "value": 100.0}, + {"display_name": "Medium Volume 🟰", "value": 150.0}, + {"display_name": "High Volume ⬆️", "value": 200.0}, + ], + description="This is a description.", + ) + case str() if type_to_test == wrong_type_in_choice_display_name: + parameters.add_str( + display_name="Pipette Name", + variable_name="pipette", + choices=[ + {"display_name": 6.0, "value": "flex_1channel_50"}, + {"display_name": "Eight Channel 50µL", "value": "flex_8channel_50"}, + ], + default="flex_8channel_50", + description="This is a description.", + ) + case str() if type_to_test == wrong_type_in_choice_value: + parameters.add_str( + display_name="Pipette Name", + variable_name="pipette", + choices=[ + {"display_name": "50", "value": 5}, + {"display_name": "Eight Channel 50µL", "value": "flex_8channel_50"}, + ], + default="flex_8channel_50", + description="This is a description.", + ) + case str() if type_to_test == wrong_type_in_default: + parameters.add_str( + display_name="Pipette Name", + variable_name="pipette", + choices=[ + {"display_name": "50", "value": "flex_8channel_1000"}, + {"display_name": "Eight Channel 50µL", "value": "flex_8channel_50"}, + ], + default=6, + description="This is a description.", + ) + case str() if type_to_test == wrong_type_in_description: + parameters.add_str( + display_name="Pipette Name", + variable_name="pipette", + choices=[ + {"display_name": "50", "value": "flex_8channel_1000"}, + {"display_name": "Eight Channel 50µL", "value": "flex_8channel_50"}, + ], + default="flex_8channel_50", + description=(), + ) + case str() if type_to_test == wrong_type_in_minimum: + parameters.add_int( + display_name="Dilutions", + variable_name="dilutions", + default=1, + minimum="1", + maximum=3, + description="This is a description.", + ) + case str() if type_to_test == wrong_type_in_maximum: + parameters.add_int( + display_name="Dilutions", + variable_name="dilutions", + default=1, + minimum=1, + maximum="3", + description="This is a description.", + ) + case str() if type_to_test == wrong_type_in_unit: + parameters.add_int( + display_name="Dilutions", + variable_name="dilutions", + default=1, + minimum=1, + maximum=3, + description="This is a description.", + unit=5, + ) + + +def run(context): + for variable_name, value in context.params.get_all().items(): + context.comment(f"variable {variable_name} has value {value}") diff --git a/app-testing/files/protocols/Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultChoiceNoMatchChoice.py b/app-testing/files/protocols/Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultChoiceNoMatchChoice.py new file mode 100644 index 00000000000..a282f63fd85 --- /dev/null +++ b/app-testing/files/protocols/Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultChoiceNoMatchChoice.py @@ -0,0 +1,61 @@ +# I am going to get added to in the test runner +# type_to_test = wrong_type_in_display_name +# protocol.override_variable_name = type_to_test + +metadata = { + "protocolName": "default choice does not match a choice", +} + +requirements = {"robotType": "Flex", "apiLevel": "2.18"} + + +# change me to test that a bad type is caught +# for each field of parameter. +# protocol.overrides is a list of these strings +str_default_no_matching_choices = "str_default_no_matching_choices" +float_default_no_matching_choices = "float_default_no_matching_choices" +int_default_no_matching_choices = "int_default_no_matching_choices" + + +def add_parameters(parameters): + match type_to_test: + case str() if type_to_test == int_default_no_matching_choices: + parameters.add_int( + display_name="Mixing Volume in µL", + variable_name="mix_in_volume", + default=10, + choices=[ + {"display_name": "Low Volume ⬇️", "value": 9}, + {"display_name": "Medium Volume 🟰", "value": 15}, + {"display_name": "High Volume ⬆️", "value": 20}, + ], + description="This is a description.", + ) + case str() if type_to_test == float_default_no_matching_choices: + parameters.add_float( + display_name="Mixing Volume in µL", + variable_name="mix_in_volume", + default=150.0, + choices=[ + {"display_name": "Low Volume ⬇️", "value": 100.0}, + {"display_name": "Medium Volume 🟰", "value": 160.0}, + {"display_name": "High Volume ⬆️", "value": 200.0}, + ], + description="This is a description.", + ) + case str() if type_to_test == str_default_no_matching_choices: + parameters.add_str( + display_name="Pipette Name", + variable_name="pipette", + choices=[ + {"display_name": "1channel", "value": "flex_1channel_50"}, + {"display_name": "Eight Channel 50µL", "value": "flex_8channel_50"}, + ], + default="I am not in the choices", + description="This is a description.", + ) + + +def run(context): + for variable_name, value in context.params.get_all().items(): + context.comment(f"variable {variable_name} has value {value}") diff --git a/app-testing/files/protocols/Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultOutOfRangeRTP.py b/app-testing/files/protocols/Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultOutOfRangeRTP.py new file mode 100644 index 00000000000..2b5764a362e --- /dev/null +++ b/app-testing/files/protocols/Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultOutOfRangeRTP.py @@ -0,0 +1,43 @@ +# I am going to get added to in the test runner +# type_to_test = default_greater_than_maximum +# protocol.override_variable_name = type_to_test + +metadata = { + "protocolName": "Default not in range", +} + +requirements = {"robotType": "Flex", "apiLevel": "2.18"} + + +# change me to test that a bad type is caught +# for each field of parameter. +# protocol.overrides is a list of these strings +default_greater_than_maximum = "default_greater_than_maximum" +default_less_than_minimum = "default_less_than_minimum" + + +def add_parameters(parameters): + match type_to_test: + case str() if type_to_test == default_greater_than_maximum: + parameters.add_int( + display_name="display name", + variable_name="dilutions", + default=4, + minimum=1, + maximum=3, + description="This is a description.", + ) + case str() if type_to_test == default_less_than_minimum: + parameters.add_int( + display_name="display name", + variable_name="dilutions", + default=0, + minimum=1, + maximum=3, + description="This is a description.", + ) + + +def run(context): + for variable_name, value in context.params.get_all().items(): + context.comment(f"variable {variable_name} has value {value}") diff --git a/app-testing/files/protocols/json/Flex_P1000_96_Gripper_TC_TM_HS_AnalysisError_GripperCollisionWithTips.json b/app-testing/files/protocols/Flex_X_v8_P1000_96_HS_GRIP_TC_TM_GripperCollisionWithTips.json similarity index 100% rename from app-testing/files/protocols/json/Flex_P1000_96_Gripper_TC_TM_HS_AnalysisError_GripperCollisionWithTips.json rename to app-testing/files/protocols/Flex_X_v8_P1000_96_HS_GRIP_TC_TM_GripperCollisionWithTips.json diff --git a/app-testing/files/protocols/py/OT2_P10S_P300M_TC1_TM_MM_2_11_Swift.py b/app-testing/files/protocols/OT2_S_v2_11_P10S_P300M_MM_TC1_TM_Swift.py similarity index 100% rename from app-testing/files/protocols/py/OT2_P10S_P300M_TC1_TM_MM_2_11_Swift.py rename to app-testing/files/protocols/OT2_S_v2_11_P10S_P300M_MM_TC1_TM_Swift.py diff --git a/app-testing/files/protocols/py/OT2_None_None_2_12_Python310SyntaxRobotAnalysisOnlyError.py b/app-testing/files/protocols/OT2_S_v2_12_NO_PIPETTES_Python310SyntaxRobotAnalysisOnlyError.py similarity index 100% rename from app-testing/files/protocols/py/OT2_None_None_2_12_Python310SyntaxRobotAnalysisOnlyError.py rename to app-testing/files/protocols/OT2_S_v2_12_NO_PIPETTES_Python310SyntaxRobotAnalysisOnlyError.py diff --git a/app-testing/files/protocols/py/OT2_P300M_P20S_None_2_12_FailOnRun.py b/app-testing/files/protocols/OT2_S_v2_12_P300M_P20S_FailOnRun.py similarity index 100% rename from app-testing/files/protocols/py/OT2_P300M_P20S_None_2_12_FailOnRun.py rename to app-testing/files/protocols/OT2_S_v2_12_P300M_P20S_FailOnRun.py diff --git a/app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_13_SmokeTestV3.py b/app-testing/files/protocols/OT2_S_v2_13_P300M_P20S_HS_TC_TM_SmokeTestV3.py similarity index 99% rename from app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_13_SmokeTestV3.py rename to app-testing/files/protocols/OT2_S_v2_13_P300M_P20S_HS_TC_TM_SmokeTestV3.py index 43a2e61dff5..da7b3ab385b 100644 --- a/app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_13_SmokeTestV3.py +++ b/app-testing/files/protocols/OT2_S_v2_13_P300M_P20S_HS_TC_TM_SmokeTestV3.py @@ -1,4 +1,5 @@ """Smoke Test v3.0 """ + # https://opentrons.atlassian.net/projects/RQA?selectedItem=com.atlassian.plugins.atlassian-connect-plugin:com.kanoah.test-manager__main-project-page#!/testCase/QB-T497 from opentrons import protocol_api diff --git a/app-testing/files/protocols/py/OT2_P300M_P20S_TC_MM_TM_2_13_Smoke620Release.py b/app-testing/files/protocols/OT2_S_v2_13_P300M_P20S_MM_TC_TM_Smoke620Release.py similarity index 100% rename from app-testing/files/protocols/py/OT2_P300M_P20S_TC_MM_TM_2_13_Smoke620Release.py rename to app-testing/files/protocols/OT2_S_v2_13_P300M_P20S_MM_TC_TM_Smoke620Release.py diff --git a/app-testing/files/protocols/py/OT2_None_None_TC_2_14_VerifyThermocyclerLoadedSlots.py b/app-testing/files/protocols/OT2_S_v2_14_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots.py similarity index 100% rename from app-testing/files/protocols/py/OT2_None_None_TC_2_14_VerifyThermocyclerLoadedSlots.py rename to app-testing/files/protocols/OT2_S_v2_14_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots.py diff --git a/app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_14_SmokeTestV3.py b/app-testing/files/protocols/OT2_S_v2_14_P300M_P20S_HS_TC_TM_SmokeTestV3.py similarity index 99% rename from app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_14_SmokeTestV3.py rename to app-testing/files/protocols/OT2_S_v2_14_P300M_P20S_HS_TC_TM_SmokeTestV3.py index 3413a55af87..4ff0f563d37 100644 --- a/app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_14_SmokeTestV3.py +++ b/app-testing/files/protocols/OT2_S_v2_14_P300M_P20S_HS_TC_TM_SmokeTestV3.py @@ -1,4 +1,5 @@ """Smoke Test v3.0 """ + # https://opentrons.atlassian.net/projects/RQA?selectedItem=com.atlassian.plugins.atlassian-connect-plugin:com.kanoah.test-manager__main-project-page#!/testCase/QB-T497 from opentrons import protocol_api diff --git a/app-testing/files/protocols/py/OT2_None_None_TC_2_15_VerifyThermocyclerLoadedSlots.py b/app-testing/files/protocols/OT2_S_v2_15_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots.py similarity index 100% rename from app-testing/files/protocols/py/OT2_None_None_TC_2_15_VerifyThermocyclerLoadedSlots.py rename to app-testing/files/protocols/OT2_S_v2_15_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots.py diff --git a/app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_15_SmokeTestV3.py b/app-testing/files/protocols/OT2_S_v2_15_P300M_P20S_HS_TC_TM_SmokeTestV3.py similarity index 99% rename from app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_15_SmokeTestV3.py rename to app-testing/files/protocols/OT2_S_v2_15_P300M_P20S_HS_TC_TM_SmokeTestV3.py index c60e647844d..aeb151c2267 100644 --- a/app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_15_SmokeTestV3.py +++ b/app-testing/files/protocols/OT2_S_v2_15_P300M_P20S_HS_TC_TM_SmokeTestV3.py @@ -1,4 +1,5 @@ """Smoke Test v3.0 """ + # https://opentrons.atlassian.net/projects/RQA?selectedItem=com.atlassian.plugins.atlassian-connect-plugin:com.kanoah.test-manager__main-project-page#!/testCase/QB-T497 from opentrons import protocol_api diff --git a/app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_15_dispense_changes.py b/app-testing/files/protocols/OT2_S_v2_15_P300M_P20S_HS_TC_TM_dispense_changes.py similarity index 100% rename from app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_15_dispense_changes.py rename to app-testing/files/protocols/OT2_S_v2_15_P300M_P20S_HS_TC_TM_dispense_changes.py diff --git a/app-testing/files/protocols/py/OT2_None_None_TC_2_16_VerifyThermocyclerLoadedSlots.py b/app-testing/files/protocols/OT2_S_v2_16_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots.py similarity index 100% rename from app-testing/files/protocols/py/OT2_None_None_TC_2_16_VerifyThermocyclerLoadedSlots.py rename to app-testing/files/protocols/OT2_S_v2_16_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots.py diff --git a/app-testing/files/protocols/py/OT2_None_None_2_16_verifyDoesNotDeadlock.py b/app-testing/files/protocols/OT2_S_v2_16_NO_PIPETTES_verifyDoesNotDeadlock.py similarity index 100% rename from app-testing/files/protocols/py/OT2_None_None_2_16_verifyDoesNotDeadlock.py rename to app-testing/files/protocols/OT2_S_v2_16_NO_PIPETTES_verifyDoesNotDeadlock.py diff --git a/app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_16_SmokeTestV3.py b/app-testing/files/protocols/OT2_S_v2_16_P300M_P20S_HS_TC_TM_SmokeTestV3.py similarity index 99% rename from app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_16_SmokeTestV3.py rename to app-testing/files/protocols/OT2_S_v2_16_P300M_P20S_HS_TC_TM_SmokeTestV3.py index b642a18e18f..4c0ceafb2ba 100644 --- a/app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_16_SmokeTestV3.py +++ b/app-testing/files/protocols/OT2_S_v2_16_P300M_P20S_HS_TC_TM_SmokeTestV3.py @@ -1,4 +1,5 @@ """Smoke Test v3.0 """ + # https://opentrons.atlassian.net/projects/RQA?selectedItem=com.atlassian.plugins.atlassian-connect-plugin:com.kanoah.test-manager__main-project-page#!/testCase/QB-T497 from opentrons import protocol_api diff --git a/app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_16_aspirateDispenseMix0Volume.py b/app-testing/files/protocols/OT2_S_v2_16_P300M_P20S_HS_TC_TM_aspirateDispenseMix0Volume.py similarity index 99% rename from app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_16_aspirateDispenseMix0Volume.py rename to app-testing/files/protocols/OT2_S_v2_16_P300M_P20S_HS_TC_TM_aspirateDispenseMix0Volume.py index edf43366e1a..f59bd2a8c0e 100644 --- a/app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_16_aspirateDispenseMix0Volume.py +++ b/app-testing/files/protocols/OT2_S_v2_16_P300M_P20S_HS_TC_TM_aspirateDispenseMix0Volume.py @@ -1,4 +1,5 @@ """Smoke Test v3.0 """ + from opentrons import protocol_api metadata = { diff --git a/app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_16_dispense_changes.py b/app-testing/files/protocols/OT2_S_v2_16_P300M_P20S_HS_TC_TM_dispense_changes.py similarity index 100% rename from app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_16_dispense_changes.py rename to app-testing/files/protocols/OT2_S_v2_16_P300M_P20S_HS_TC_TM_dispense_changes.py diff --git a/app-testing/files/protocols/py/OT2_P300M_P20S_2_16_aspirateDispenseMix0Volume.py b/app-testing/files/protocols/OT2_S_v2_16_P300M_P20S_aspirateDispenseMix0Volume.py similarity index 99% rename from app-testing/files/protocols/py/OT2_P300M_P20S_2_16_aspirateDispenseMix0Volume.py rename to app-testing/files/protocols/OT2_S_v2_16_P300M_P20S_aspirateDispenseMix0Volume.py index caa4233b1a2..035a4319388 100644 --- a/app-testing/files/protocols/py/OT2_P300M_P20S_2_16_aspirateDispenseMix0Volume.py +++ b/app-testing/files/protocols/OT2_S_v2_16_P300M_P20S_aspirateDispenseMix0Volume.py @@ -1,4 +1,5 @@ """Smoke Test v3.0 """ + from opentrons import protocol_api metadata = { diff --git a/app-testing/files/protocols/py/OT2_P300S_None_2_16_verifyNoFloatingPointErrorInPipetting.py b/app-testing/files/protocols/OT2_S_v2_16_P300S_None_verifyNoFloatingPointErrorInPipetting.py similarity index 100% rename from app-testing/files/protocols/py/OT2_P300S_None_2_16_verifyNoFloatingPointErrorInPipetting.py rename to app-testing/files/protocols/OT2_S_v2_16_P300S_None_verifyNoFloatingPointErrorInPipetting.py diff --git a/app-testing/files/protocols/py/OT2_None_None_TC_2_17_VerifyThermocyclerLoadedSlots.py b/app-testing/files/protocols/OT2_S_v2_17_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots.py similarity index 100% rename from app-testing/files/protocols/py/OT2_None_None_TC_2_17_VerifyThermocyclerLoadedSlots.py rename to app-testing/files/protocols/OT2_S_v2_17_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots.py diff --git a/app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_17_SmokeTestV3.py b/app-testing/files/protocols/OT2_S_v2_17_P300M_P20S_HS_TC_TM_SmokeTestV3.py similarity index 99% rename from app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_17_SmokeTestV3.py rename to app-testing/files/protocols/OT2_S_v2_17_P300M_P20S_HS_TC_TM_SmokeTestV3.py index fdb7c172256..1c0c1f9802d 100644 --- a/app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_17_SmokeTestV3.py +++ b/app-testing/files/protocols/OT2_S_v2_17_P300M_P20S_HS_TC_TM_SmokeTestV3.py @@ -1,4 +1,5 @@ """Smoke Test v3.0 """ + # https://opentrons.atlassian.net/projects/RQA?selectedItem=com.atlassian.plugins.atlassian-connect-plugin:com.kanoah.test-manager__main-project-page#!/testCase/QB-T497 from opentrons import protocol_api diff --git a/app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_17_dispense_changes.py b/app-testing/files/protocols/OT2_S_v2_17_P300M_P20S_HS_TC_TM_dispense_changes.py similarity index 100% rename from app-testing/files/protocols/py/OT2_P300M_P20S_TC_HS_TM_2_17_dispense_changes.py rename to app-testing/files/protocols/OT2_S_v2_17_P300M_P20S_HS_TC_TM_dispense_changes.py diff --git a/app-testing/files/protocols/OT2_S_v2_18_NO_PIPETTES_GoldenRTP_OT2.py b/app-testing/files/protocols/OT2_S_v2_18_NO_PIPETTES_GoldenRTP_OT2.py new file mode 100644 index 00000000000..849dcac9383 --- /dev/null +++ b/app-testing/files/protocols/OT2_S_v2_18_NO_PIPETTES_GoldenRTP_OT2.py @@ -0,0 +1,229 @@ +metadata = { + "protocolName": "Golden RTP Examples OT2", +} + +requirements = {"robotType": "OT-2", "apiLevel": "2.18"} + +description: str = "Reused description for all parameters." +unit: str = "unit" + +# parameters with choice having non unique values is acceptable and covered in another protocol +# parameters with display_name="" and description="" is acceptable but silly - no good rule possible to protect against that + + +def add_parameters(parameters): + ###################INT##################### + ### int min/max with all fields ### + parameters.add_int( + display_name="int min/max all", # max 30 chars + variable_name="min_max_all_fields", + default=6, + minimum=1, + maximum=12, + description=description, # optional 100 characters max + unit=unit, + ) + #### int min/max without unit ### + parameters.add_int( + display_name="int min/max no unit", + variable_name="int_min_max_without_unit", + default=1, + minimum=1, + maximum=3, + description=description, + # unit is missing + ) + #### int min/max without description ### + parameters.add_int( + display_name="int min/max no description", + variable_name="int_min_max_without_description", + default=1, + minimum=1, + maximum=3, + # description is missing + unit=unit, + ) + #### int min/max without unit and description ### + parameters.add_int( + display_name="int min/max no unit,desc", + variable_name="int_min_max_without_unit_and_description", + default=1, + minimum=1, + maximum=3, + # description is missing + # unit is missing + ) + #### int choices with all fields and unique choice values ### + parameters.add_int( + display_name="int choices all", + variable_name="int_choices_all_fields", + description=description, + unit=unit, + default=20, + choices=[ + {"display_name": "20", "value": 20}, + {"display_name": "16", "value": 16}, + ], + ) + #### int choices without unit and unique choice values ### + parameters.add_int( + display_name="int choice no unit", + variable_name="int_choice_no_unit", + default=6, + description=description, + # unit is missing + choices=[ + {"display_name": "1X", "value": 6}, + {"display_name": "2X", "value": 12}, + ], + ) + #### int choices without unit or description and unique choice values ### + parameters.add_int( + display_name="int choice no unit, desc", + variable_name="int_choice_no_unit_desc", + default=10, + # description is missing + # unit is missing + choices=[ + {"display_name": "10X", "value": 10}, + {"display_name": "100X", "value": 100}, + ], + ) + ###################FLOAT##################### + #### float min/max with all fields ### + parameters.add_float( + display_name="float min/max all fields", + variable_name="float_min_max_all_fields", + default=30.0, + minimum=20.0, + maximum=30.0, + description=description, + unit=unit, + ) + #### float min/max without unit ### + parameters.add_float( + display_name="float min/max no unit", + variable_name="float_min_max_no_unit", + default=1.8, + minimum=1.5, + maximum=3.0, + description=description, + # unit is missing + ) + #### float min/max without unit or description ### + parameters.add_float( + display_name="float min/max no unit,desc", + variable_name="float_min_max_no_unit_or_desc", + default=1.8, + minimum=1.5, + maximum=3.0, + # description is missing + # unit is missing + ) + #### float choices with all and unique choice values ### + parameters.add_float( + display_name="float choices all", + variable_name="float_choices_all_fields", + default=20.0, + choices=[ + {"display_name": "Low Volume (10.0µL)", "value": 10.0}, + {"display_name": "Medium Volume (20.0µL)", "value": 20.0}, + {"display_name": "High Volume (50.0µL)", "value": 50.0}, + ], + description=description, + unit=unit, + ) + #### float choices with without unit and unique choice values ### + parameters.add_float( + display_name="float choices no unit", + variable_name="float_choices_no_unit", + default=10.0, + choices=[ + {"display_name": "Low Volume (10.0µL)", "value": 10.0}, + {"display_name": "High Volume (50.0µL)", "value": 50.0}, + ], + description=description, + # unit is missing + ) + #### float choices without description and unique choice values ### + parameters.add_float( + display_name="float choices no description", + variable_name="float_choices_no_description", + default=20.0, + choices=[ + {"display_name": "Low Volume (10.0µL)", "value": 10.0}, + {"display_name": "Medium Volume (20.0µL)", "value": 20.0}, + {"display_name": "High Volume (50.0µL)", "value": 50.0}, + ], + # description is missing + unit=unit, + ) + #### float choices with without unit or description and unique choice values ### + parameters.add_float( + display_name="float choices no unit,desc", + variable_name="float_choices_no_unit_or_desc", + default=20.0, + choices=[ + {"display_name": "Low Volume (10.0µL)", "value": 10.0}, + {"display_name": "Medium Volume (20.0µL)", "value": 20.0}, + {"display_name": "High Volume (50.0µL)", "value": 50.0}, + ], + # description is missing + # unit is missing + ) + ###################BOOL##################### + parameters.add_bool( + display_name="bool all fields", + variable_name="bool_all_fields", + default=False, + description="When on, skip aspirate and dispense steps.", + ) + parameters.add_bool( + display_name="bool no description", + variable_name="bool_no_desc", + default=False, + # description is missing + ) + ###################STR##################### + #### str all fields and unique choice values ### + parameters.add_str( + display_name="str choices all", + variable_name="str_choices_all_fields", + choices=[ + {"display_name": "Single channel 50µL", "value": "flex_1channel_50"}, + {"display_name": "Eight Channel 50µL", "value": "flex_8channel_50"}, + ], + default="flex_1channel_50", + description="What pipette to use during the protocol.", + ) + #### str all fields and unique choice values ### + parameters.add_str( + display_name="str choices all many", + variable_name="str_choices_all_many_fields", + choices=[ + {"display_name": "A", "value": "A"}, + {"display_name": "B", "value": "B"}, + {"display_name": "C", "value": "C"}, + {"display_name": "D", "value": "D"}, + {"display_name": "E", "value": "E"}, + {"display_name": "F", "value": "F"}, + ], + default="E", + description=description, + ) + #### str no description and unique choice values ### + parameters.add_str( + display_name="str choices no desc", + variable_name="str_choices_no_desc", + choices=[ + {"display_name": "Single channel 50µL", "value": "flex_1channel_50"}, + {"display_name": "Eight Channel 50µL", "value": "flex_8channel_50"}, + ], + default="flex_1channel_50", + # description is missing + ) + + +def run(context): + for variable_name, value in context.params.get_all().items(): + context.comment(f"variable {variable_name} has value {value}") diff --git a/app-testing/files/protocols/OT2_S_v2_18_None_None_duplicateChoiceValue.py b/app-testing/files/protocols/OT2_S_v2_18_None_None_duplicateChoiceValue.py new file mode 100644 index 00000000000..8e183036e68 --- /dev/null +++ b/app-testing/files/protocols/OT2_S_v2_18_None_None_duplicateChoiceValue.py @@ -0,0 +1,27 @@ +metadata = { + "protocolName": "Duplicate choice value", +} + +requirements = {"robotType": "OT-2", "apiLevel": "2.18"} + +# we allow duplicate choice values,even for the default +# validated this does not cause any issues in the app as well - 4/12/2014 ✅ it does not. + + +def add_parameters(parameters): + parameters.add_str( + display_name="Pipette Name", + variable_name="pipette", + choices=[ + {"display_name": "Single channel 50µL", "value": "flex_1channel_50"}, + {"display_name": "Eight Channel 50µL", "value": "flex_8channel_50"}, + {"display_name": "Single channel 50µL again", "value": "flex_1channel_50"}, # duplicate choice value + ], + default="flex_1channel_50", + description="What pipette to use during the protocol.", + ) + + +def run(context): + for variable_name, value in context.params.get_all().items(): + context.comment(f"variable {variable_name} has value {value}") diff --git a/app-testing/files/protocols/py/OT2_P300SLeft_MM1_MM_2_2_EngageMagHeightFromBase.py b/app-testing/files/protocols/OT2_S_v2_2_P300S_None_MM1_MM2_EngageMagHeightFromBase.py similarity index 100% rename from app-testing/files/protocols/py/OT2_P300SLeft_MM1_MM_2_2_EngageMagHeightFromBase.py rename to app-testing/files/protocols/OT2_S_v2_2_P300S_None_MM1_MM2_EngageMagHeightFromBase.py diff --git a/app-testing/files/protocols/py/OT2_P300SLeft_MM1_MM_TM_2_3_Mix.py b/app-testing/files/protocols/OT2_S_v2_3_P300S_None_MM1_MM2_TM_Mix.py similarity index 100% rename from app-testing/files/protocols/py/OT2_P300SLeft_MM1_MM_TM_2_3_Mix.py rename to app-testing/files/protocols/OT2_S_v2_3_P300S_None_MM1_MM2_TM_Mix.py diff --git a/app-testing/files/protocols/py/OT2_P300MLeft_MM_TM_2_4_Zymo.py b/app-testing/files/protocols/OT2_S_v2_4_P300M_None_MM_TM_Zymo.py similarity index 100% rename from app-testing/files/protocols/py/OT2_P300MLeft_MM_TM_2_4_Zymo.py rename to app-testing/files/protocols/OT2_S_v2_4_P300M_None_MM_TM_Zymo.py diff --git a/app-testing/files/protocols/py/OT2_P20S_None_2_7_Walkthrough.py b/app-testing/files/protocols/OT2_S_v2_7_P20S_None_Walkthrough.py similarity index 100% rename from app-testing/files/protocols/py/OT2_P20S_None_2_7_Walkthrough.py rename to app-testing/files/protocols/OT2_S_v2_7_P20S_None_Walkthrough.py diff --git a/app-testing/files/protocols/json/OT2_P300SG1_None_5_2_6_Gen1PipetteSimple.json b/app-testing/files/protocols/OT2_S_v3_P300SGen1_None_Gen1PipetteSimple.json similarity index 100% rename from app-testing/files/protocols/json/OT2_P300SG1_None_5_2_6_Gen1PipetteSimple.json rename to app-testing/files/protocols/OT2_S_v3_P300SGen1_None_Gen1PipetteSimple.json diff --git a/app-testing/files/protocols/json/OT2_P300M_P20S_MM_TM_TC1_5_2_6_PD40.json b/app-testing/files/protocols/OT2_S_v4_P300M_P20S_MM_TM_TC1_PD40.json similarity index 100% rename from app-testing/files/protocols/json/OT2_P300M_P20S_MM_TM_TC1_5_2_6_PD40.json rename to app-testing/files/protocols/OT2_S_v4_P300M_P20S_MM_TM_TC1_PD40.json diff --git a/app-testing/files/protocols/json/OT2_P300SLeft_MM_TM_TM_5_2_6_MOAMTemps.json b/app-testing/files/protocols/OT2_S_v4_P300S_None_MM_TM_TM_MOAMTemps.json similarity index 100% rename from app-testing/files/protocols/json/OT2_P300SLeft_MM_TM_TM_5_2_6_MOAMTemps.json rename to app-testing/files/protocols/OT2_S_v4_P300S_None_MM_TM_TM_MOAMTemps.json diff --git a/app-testing/files/protocols/json/OT2_P1000SLeft_None_6_1_SimpleTransfer.json b/app-testing/files/protocols/OT2_S_v6_P1000S_None_SimpleTransfer.json similarity index 100% rename from app-testing/files/protocols/json/OT2_P1000SLeft_None_6_1_SimpleTransfer.json rename to app-testing/files/protocols/OT2_S_v6_P1000S_None_SimpleTransfer.json diff --git a/app-testing/files/protocols/json/OT2_P20S_P300M_NoMods_6_1_TransferReTransferLiquid.json b/app-testing/files/protocols/OT2_S_v6_P20S_P300M_TransferReTransferLiquid.json similarity index 100% rename from app-testing/files/protocols/json/OT2_P20S_P300M_NoMods_6_1_TransferReTransferLiquid.json rename to app-testing/files/protocols/OT2_S_v6_P20S_P300M_TransferReTransferLiquid.json diff --git a/app-testing/files/protocols/json/OT2_P300M_P20S_HS_6_1_Smoke620release.json b/app-testing/files/protocols/OT2_S_v6_P300M_P20S_HS_Smoke620release.json similarity index 100% rename from app-testing/files/protocols/json/OT2_P300M_P20S_HS_6_1_Smoke620release.json rename to app-testing/files/protocols/OT2_S_v6_P300M_P20S_HS_Smoke620release.json diff --git a/app-testing/files/protocols/json/OT2_P300M_P20S_NoMod_6_1_MixTransferManyLiquids.json b/app-testing/files/protocols/OT2_S_v6_P300M_P20S_MixTransferManyLiquids.json similarity index 100% rename from app-testing/files/protocols/json/OT2_P300M_P20S_NoMod_6_1_MixTransferManyLiquids.json rename to app-testing/files/protocols/OT2_S_v6_P300M_P20S_MixTransferManyLiquids.json diff --git a/app-testing/files/protocols/json/OT2_P300M_P300S_HS_6_1_HS_NormalUseWithTransfer.json b/app-testing/files/protocols/OT2_S_v6_P300M_P300S_HS_HS_NormalUseWithTransfer.json similarity index 100% rename from app-testing/files/protocols/json/OT2_P300M_P300S_HS_6_1_HS_NormalUseWithTransfer.json rename to app-testing/files/protocols/OT2_S_v6_P300M_P300S_HS_HS_NormalUseWithTransfer.json diff --git a/app-testing/files/protocols/py/OT2_P300S_Thermocycler_Moam_Error.py b/app-testing/files/protocols/OT2_X_v2_11_P300S_TC1_TC2_ThermocyclerMoamError.py similarity index 100% rename from app-testing/files/protocols/py/OT2_P300S_Thermocycler_Moam_Error.py rename to app-testing/files/protocols/OT2_X_v2_11_P300S_TC1_TC2_ThermocyclerMoamError.py diff --git a/app-testing/files/protocols/py/OT2_None_None_2_13_PythonSyntaxError.py b/app-testing/files/protocols/OT2_X_v2_13_None_None_PythonSyntaxError.py similarity index 100% rename from app-testing/files/protocols/py/OT2_None_None_2_13_PythonSyntaxError.py rename to app-testing/files/protocols/OT2_X_v2_13_None_None_PythonSyntaxError.py diff --git a/app-testing/files/protocols/py/OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin1.py b/app-testing/files/protocols/OT2_X_v2_16_None_None_HS_HeaterShakerConflictWithTrashBin1.py similarity index 100% rename from app-testing/files/protocols/py/OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin1.py rename to app-testing/files/protocols/OT2_X_v2_16_None_None_HS_HeaterShakerConflictWithTrashBin1.py diff --git a/app-testing/files/protocols/py/OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin2.py b/app-testing/files/protocols/OT2_X_v2_16_None_None_HS_HeaterShakerConflictWithTrashBin2.py similarity index 100% rename from app-testing/files/protocols/py/OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin2.py rename to app-testing/files/protocols/OT2_X_v2_16_None_None_HS_HeaterShakerConflictWithTrashBin2.py diff --git a/app-testing/files/protocols/OT2_X_v2_18_None_None_NoRTPdisplay_name.py b/app-testing/files/protocols/OT2_X_v2_18_None_None_NoRTPdisplay_name.py new file mode 100644 index 00000000000..116ca8b5dd5 --- /dev/null +++ b/app-testing/files/protocols/OT2_X_v2_18_None_None_NoRTPdisplay_name.py @@ -0,0 +1,23 @@ +metadata = { + "protocolName": "No RTP Display Name", +} + +requirements = {"robotType": "OT-2", "apiLevel": "2.18"} + +just_right: str = "This is a description" + + +def add_parameters(parameters): + parameters.add_int( + # display_name is missing + variable_name="variable_a", + default=1, + minimum=1, + maximum=3, + description=just_right, + ) + + +def run(context): + for variable_name, value in context.params.get_all().items(): + context.comment(f"variable {variable_name} has value {value}") diff --git a/app-testing/files/protocols/OT2_X_v2_18_None_None_StrRTPwith_unit.py b/app-testing/files/protocols/OT2_X_v2_18_None_None_StrRTPwith_unit.py new file mode 100644 index 00000000000..2ecef4632aa --- /dev/null +++ b/app-testing/files/protocols/OT2_X_v2_18_None_None_StrRTPwith_unit.py @@ -0,0 +1,27 @@ +metadata = { + "protocolName": "Str RTP with unit", +} + +requirements = {"robotType": "OT-2", "apiLevel": "2.18"} + +just_right: str = "This is a description" + + +def add_parameters(parameters): + parameters.add_str( + display_name="display name", + variable_name="variable_a", + default="one", + choices=[ + {"value": "one", "display": "one"}, + {"value": "two", "display": "two"}, + ], + description=just_right, + unit="unit", # I cause the error + ) + ## TODO: str with unit,min,max + + +def run(context): + for variable_name, value in context.params.get_all().items(): + context.comment(f"variable {variable_name} has value {value}") diff --git a/app-testing/files/protocols/OT2_X_v2_18_None_None_duplicateRTPVariableName.py b/app-testing/files/protocols/OT2_X_v2_18_None_None_duplicateRTPVariableName.py new file mode 100644 index 00000000000..b5ff38dbbcf --- /dev/null +++ b/app-testing/files/protocols/OT2_X_v2_18_None_None_duplicateRTPVariableName.py @@ -0,0 +1,40 @@ +metadata = { + "protocolName": "Multiple RTP Variables with Same Name", +} + +requirements = {"robotType": "OT-2", "apiLevel": "2.18"} + +just_right: str = "This is a description" + + +def add_parameters(parameters): + parameters.add_int( + display_name="int 1", + variable_name="variable_a", + default=1, + minimum=1, + maximum=3, + description=just_right, + ) + parameters.add_int( + display_name="int 2", + variable_name="variable_b", + default=1, + minimum=1, + maximum=3, + description=just_right, + ) + + parameters.add_int( + display_name="int 3", + variable_name="variable_a", # duplicate variable name + default=1, + minimum=1, + maximum=3, + description=just_right, + ) + + +def run(context): + for variable_name, value in context.params.get_all().items(): + context.comment(f"variable {variable_name} has value {value}") diff --git a/app-testing/files/protocols/py/OT2_P300S_Twinning_Error.py b/app-testing/files/protocols/OT2_X_v2_7_P300S_TwinningError.py similarity index 100% rename from app-testing/files/protocols/py/OT2_P300S_Twinning_Error.py rename to app-testing/files/protocols/OT2_X_v2_7_P300S_TwinningError.py diff --git a/app-testing/files/protocols/json/OT2_P300M_P20S_MM_TM_TC1_5_2_6_PD40Error.json b/app-testing/files/protocols/OT2_X_v4_P300M_P20S_MM_TC1_TM_e2eTests.json similarity index 100% rename from app-testing/files/protocols/json/OT2_P300M_P20S_MM_TM_TC1_5_2_6_PD40Error.json rename to app-testing/files/protocols/OT2_X_v4_P300M_P20S_MM_TC1_TM_e2eTests.json diff --git a/app-testing/files/protocols/json/OT2_P20SRight_None_6_1_SimpleTransferError.json b/app-testing/files/protocols/OT2_X_v6_P20S_None_SimpleTransfer.json similarity index 100% rename from app-testing/files/protocols/json/OT2_P20SRight_None_6_1_SimpleTransferError.json rename to app-testing/files/protocols/OT2_X_v6_P20S_None_SimpleTransfer.json diff --git a/app-testing/files/protocols/OT2_X_v6_P20S_P300M_HS_HSCollision.json b/app-testing/files/protocols/OT2_X_v6_P20S_P300M_HS_HSCollision.json new file mode 100644 index 00000000000..41099556baf --- /dev/null +++ b/app-testing/files/protocols/OT2_X_v6_P20S_P300M_HS_HSCollision.json @@ -0,0 +1,3981 @@ +{ + "metadata": { + "protocolName": "HS Collision", + "author": "", + "description": "", + "created": 1660146567413, + "lastModified": 1660146926908, + "category": null, + "subcategory": null, + "tags": [] + }, + "designerApplication": { + "name": "opentrons/protocol-designer", + "version": "6.0.0", + "data": { + "_internalAppBuildDate": "Mon, 08 Aug 2022 21:31:42 GMT", + "defaultValues": { + "aspirate_mmFromBottom": 1, + "dispense_mmFromBottom": 0.5, + "touchTip_mmFromTop": -1, + "blowout_mmFromTop": 0 + }, + "pipetteTiprackAssignments": { + "d7e73681-8957-4063-8ce1-38c12373ec39": "opentrons/opentrons_96_tiprack_300ul/1", + "f5937b23-677d-4cff-bc10-224cf022858c": "opentrons/opentrons_96_tiprack_300ul/1" + }, + "dismissedWarnings": { + "form": {}, + "timeline": {} + }, + "ingredients": { + "0": { + "name": "Water", + "displayColor": "#b925ff", + "description": null, + "serialize": false, + "liquidGroupId": "0" + } + }, + "ingredLocations": { + "dbed30a1-d5d7-48b7-82f6-284a20b06118:opentrons/armadillo_96_wellplate_200ul_pcr_full_skirt/1": { + "A1": { + "0": { + "volume": 100 + } + }, + "B1": { + "0": { + "volume": 100 + } + }, + "C1": { + "0": { + "volume": 100 + } + }, + "D1": { + "0": { + "volume": 100 + } + }, + "E1": { + "0": { + "volume": 100 + } + }, + "F1": { + "0": { + "volume": 100 + } + }, + "G1": { + "0": { + "volume": 100 + } + }, + "H1": { + "0": { + "volume": 100 + } + }, + "A2": { + "0": { + "volume": 100 + } + }, + "B2": { + "0": { + "volume": 100 + } + }, + "C2": { + "0": { + "volume": 100 + } + }, + "D2": { + "0": { + "volume": 100 + } + }, + "E2": { + "0": { + "volume": 100 + } + }, + "F2": { + "0": { + "volume": 100 + } + }, + "G2": { + "0": { + "volume": 100 + } + }, + "H2": { + "0": { + "volume": 100 + } + }, + "A3": { + "0": { + "volume": 100 + } + }, + "B3": { + "0": { + "volume": 100 + } + }, + "C3": { + "0": { + "volume": 100 + } + }, + "D3": { + "0": { + "volume": 100 + } + }, + "E3": { + "0": { + "volume": 100 + } + }, + "F3": { + "0": { + "volume": 100 + } + }, + "G3": { + "0": { + "volume": 100 + } + }, + "H3": { + "0": { + "volume": 100 + } + } + } + }, + "savedStepForms": { + "__INITIAL_DECK_SETUP_STEP__": { + "stepType": "manualIntervention", + "id": "__INITIAL_DECK_SETUP_STEP__", + "labwareLocationUpdate": { + "fixedTrash": "12", + "1a8aeb5d-d5df-41b2-a794-ff967118e126:opentrons/opentrons_96_tiprack_300ul/1": "2", + "59b6af9f-7b2f-4007-a5ef-ef60d38939dc:opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1": "b8a48baa-1ee2-448d-8680-c7126843cbe4:heaterShakerModuleType", + "3268de61-0657-4a48-8e63-0c3b4bf502a1:opentrons/opentrons_96_tiprack_300ul/1": "4", + "dbed30a1-d5d7-48b7-82f6-284a20b06118:opentrons/armadillo_96_wellplate_200ul_pcr_full_skirt/1": "5" + }, + "pipetteLocationUpdate": { + "d7e73681-8957-4063-8ce1-38c12373ec39": "left", + "f5937b23-677d-4cff-bc10-224cf022858c": "right" + }, + "moduleLocationUpdate": { + "b8a48baa-1ee2-448d-8680-c7126843cbe4:heaterShakerModuleType": "1" + } + }, + "a8fa1851-736f-4769-bd5a-7f7bc2dbef89": { + "id": "a8fa1851-736f-4769-bd5a-7f7bc2dbef89", + "stepType": "moveLiquid", + "stepName": "transfer", + "stepDetails": "", + "pipette": "f5937b23-677d-4cff-bc10-224cf022858c", + "volume": "100", + "changeTip": "always", + "path": "single", + "aspirate_wells_grouped": false, + "aspirate_flowRate": null, + "aspirate_labware": "dbed30a1-d5d7-48b7-82f6-284a20b06118:opentrons/armadillo_96_wellplate_200ul_pcr_full_skirt/1", + "aspirate_wells": [ + "A1" + ], + "aspirate_wellOrder_first": "t2b", + "aspirate_wellOrder_second": "l2r", + "aspirate_mix_checkbox": false, + "aspirate_mix_times": null, + "aspirate_mix_volume": null, + "aspirate_mmFromBottom": null, + "aspirate_touchTip_checkbox": false, + "aspirate_touchTip_mmFromBottom": null, + "dispense_flowRate": null, + "dispense_labware": "59b6af9f-7b2f-4007-a5ef-ef60d38939dc:opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1", + "dispense_wells": [ + "A2", + "A12" + ], + "dispense_wellOrder_first": "t2b", + "dispense_wellOrder_second": "l2r", + "dispense_mix_checkbox": false, + "dispense_mix_times": null, + "dispense_mix_volume": null, + "dispense_mmFromBottom": null, + "dispense_touchTip_checkbox": false, + "dispense_touchTip_mmFromBottom": null, + "disposalVolume_checkbox": true, + "disposalVolume_volume": "20", + "blowout_checkbox": false, + "blowout_location": "fixedTrash", + "preWetTip": false, + "aspirate_airGap_checkbox": false, + "aspirate_airGap_volume": "20", + "aspirate_delay_checkbox": false, + "aspirate_delay_mmFromBottom": null, + "aspirate_delay_seconds": "1", + "dispense_airGap_checkbox": false, + "dispense_airGap_volume": "20", + "dispense_delay_checkbox": false, + "dispense_delay_seconds": "1", + "dispense_delay_mmFromBottom": null + }, + "aed6019f-ef5d-4420-8611-f7b4aa7b5d93": { + "id": "aed6019f-ef5d-4420-8611-f7b4aa7b5d93", + "stepType": "heaterShaker", + "stepName": "heater-shaker", + "stepDetails": "", + "moduleId": "b8a48baa-1ee2-448d-8680-c7126843cbe4:heaterShakerModuleType", + "setHeaterShakerTemperature": null, + "targetHeaterShakerTemperature": null, + "targetSpeed": null, + "setShake": null, + "latchOpen": false, + "heaterShakerSetTimer": null, + "heaterShakerTimerMinutes": null, + "heaterShakerTimerSeconds": null + } + }, + "orderedStepIds": [ + "aed6019f-ef5d-4420-8611-f7b4aa7b5d93", + "a8fa1851-736f-4769-bd5a-7f7bc2dbef89" + ] + } + }, + "robot": { + "model": "OT-2 Standard", + "deckId": "ot2_standard" + }, + "pipettes": { + "d7e73681-8957-4063-8ce1-38c12373ec39": { + "name": "p300_single_gen2" + }, + "f5937b23-677d-4cff-bc10-224cf022858c": { + "name": "p300_multi_gen2" + } + }, + "labware": { + "fixedTrash": { + "displayName": "Trash", + "definitionId": "opentrons/opentrons_1_trash_1100ml_fixed/1" + }, + "1a8aeb5d-d5df-41b2-a794-ff967118e126:opentrons/opentrons_96_tiprack_300ul/1": { + "displayName": "Opentrons 96 Tip Rack 300 µL", + "definitionId": "opentrons/opentrons_96_tiprack_300ul/1" + }, + "59b6af9f-7b2f-4007-a5ef-ef60d38939dc:opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1": { + "displayName": "H/S", + "definitionId": "opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1" + }, + "3268de61-0657-4a48-8e63-0c3b4bf502a1:opentrons/opentrons_96_tiprack_300ul/1": { + "displayName": "Opentrons 96 Tip Rack 300 µL (1)", + "definitionId": "opentrons/opentrons_96_tiprack_300ul/1" + }, + "dbed30a1-d5d7-48b7-82f6-284a20b06118:opentrons/armadillo_96_wellplate_200ul_pcr_full_skirt/1": { + "displayName": "1", + "definitionId": "opentrons/armadillo_96_wellplate_200ul_pcr_full_skirt/1" + } + }, + "liquids": { + "0": { + "displayName": "Water", + "description": "", + "displayColor": "#b925ff" + } + }, + "labwareDefinitions": { + "opentrons/opentrons_96_tiprack_300ul/1": { + "ordering": [ + [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1" + ], + [ + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2" + ], + [ + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3" + ], + [ + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4" + ], + [ + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5" + ], + [ + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6" + ], + [ + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7" + ], + [ + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8" + ], + [ + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9" + ], + [ + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10" + ], + [ + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11" + ], + [ + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ] + ], + "brand": { + "brand": "Opentrons", + "brandId": [], + "links": [ + "https://shop.opentrons.com/collections/opentrons-tips/products/opentrons-300ul-tips" + ] + }, + "metadata": { + "displayName": "Opentrons 96 Tip Rack 300 µL", + "displayCategory": "tipRack", + "displayVolumeUnits": "µL", + "tags": [] + }, + "dimensions": { + "xDimension": 127.76, + "yDimension": 85.48, + "zDimension": 64.49 + }, + "wells": { + "A1": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 14.38, + "y": 74.24, + "z": 5.39 + }, + "B1": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 14.38, + "y": 65.24, + "z": 5.39 + }, + "C1": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 14.38, + "y": 56.24, + "z": 5.39 + }, + "D1": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 14.38, + "y": 47.24, + "z": 5.39 + }, + "E1": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 14.38, + "y": 38.24, + "z": 5.39 + }, + "F1": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 14.38, + "y": 29.24, + "z": 5.39 + }, + "G1": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 14.38, + "y": 20.24, + "z": 5.39 + }, + "H1": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 14.38, + "y": 11.24, + "z": 5.39 + }, + "A2": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 23.38, + "y": 74.24, + "z": 5.39 + }, + "B2": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 23.38, + "y": 65.24, + "z": 5.39 + }, + "C2": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 23.38, + "y": 56.24, + "z": 5.39 + }, + "D2": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 23.38, + "y": 47.24, + "z": 5.39 + }, + "E2": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 23.38, + "y": 38.24, + "z": 5.39 + }, + "F2": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 23.38, + "y": 29.24, + "z": 5.39 + }, + "G2": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 23.38, + "y": 20.24, + "z": 5.39 + }, + "H2": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 23.38, + "y": 11.24, + "z": 5.39 + }, + "A3": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 32.38, + "y": 74.24, + "z": 5.39 + }, + "B3": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 32.38, + "y": 65.24, + "z": 5.39 + }, + "C3": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 32.38, + "y": 56.24, + "z": 5.39 + }, + "D3": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 32.38, + "y": 47.24, + "z": 5.39 + }, + "E3": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 32.38, + "y": 38.24, + "z": 5.39 + }, + "F3": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 32.38, + "y": 29.24, + "z": 5.39 + }, + "G3": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 32.38, + "y": 20.24, + "z": 5.39 + }, + "H3": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 32.38, + "y": 11.24, + "z": 5.39 + }, + "A4": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 41.38, + "y": 74.24, + "z": 5.39 + }, + "B4": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 41.38, + "y": 65.24, + "z": 5.39 + }, + "C4": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 41.38, + "y": 56.24, + "z": 5.39 + }, + "D4": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 41.38, + "y": 47.24, + "z": 5.39 + }, + "E4": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 41.38, + "y": 38.24, + "z": 5.39 + }, + "F4": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 41.38, + "y": 29.24, + "z": 5.39 + }, + "G4": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 41.38, + "y": 20.24, + "z": 5.39 + }, + "H4": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 41.38, + "y": 11.24, + "z": 5.39 + }, + "A5": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 50.38, + "y": 74.24, + "z": 5.39 + }, + "B5": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 50.38, + "y": 65.24, + "z": 5.39 + }, + "C5": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 50.38, + "y": 56.24, + "z": 5.39 + }, + "D5": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 50.38, + "y": 47.24, + "z": 5.39 + }, + "E5": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 50.38, + "y": 38.24, + "z": 5.39 + }, + "F5": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 50.38, + "y": 29.24, + "z": 5.39 + }, + "G5": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 50.38, + "y": 20.24, + "z": 5.39 + }, + "H5": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 50.38, + "y": 11.24, + "z": 5.39 + }, + "A6": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 59.38, + "y": 74.24, + "z": 5.39 + }, + "B6": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 59.38, + "y": 65.24, + "z": 5.39 + }, + "C6": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 59.38, + "y": 56.24, + "z": 5.39 + }, + "D6": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 59.38, + "y": 47.24, + "z": 5.39 + }, + "E6": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 59.38, + "y": 38.24, + "z": 5.39 + }, + "F6": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 59.38, + "y": 29.24, + "z": 5.39 + }, + "G6": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 59.38, + "y": 20.24, + "z": 5.39 + }, + "H6": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 59.38, + "y": 11.24, + "z": 5.39 + }, + "A7": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 68.38, + "y": 74.24, + "z": 5.39 + }, + "B7": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 68.38, + "y": 65.24, + "z": 5.39 + }, + "C7": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 68.38, + "y": 56.24, + "z": 5.39 + }, + "D7": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 68.38, + "y": 47.24, + "z": 5.39 + }, + "E7": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 68.38, + "y": 38.24, + "z": 5.39 + }, + "F7": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 68.38, + "y": 29.24, + "z": 5.39 + }, + "G7": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 68.38, + "y": 20.24, + "z": 5.39 + }, + "H7": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 68.38, + "y": 11.24, + "z": 5.39 + }, + "A8": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 77.38, + "y": 74.24, + "z": 5.39 + }, + "B8": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 77.38, + "y": 65.24, + "z": 5.39 + }, + "C8": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 77.38, + "y": 56.24, + "z": 5.39 + }, + "D8": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 77.38, + "y": 47.24, + "z": 5.39 + }, + "E8": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 77.38, + "y": 38.24, + "z": 5.39 + }, + "F8": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 77.38, + "y": 29.24, + "z": 5.39 + }, + "G8": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 77.38, + "y": 20.24, + "z": 5.39 + }, + "H8": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 77.38, + "y": 11.24, + "z": 5.39 + }, + "A9": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 86.38, + "y": 74.24, + "z": 5.39 + }, + "B9": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 86.38, + "y": 65.24, + "z": 5.39 + }, + "C9": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 86.38, + "y": 56.24, + "z": 5.39 + }, + "D9": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 86.38, + "y": 47.24, + "z": 5.39 + }, + "E9": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 86.38, + "y": 38.24, + "z": 5.39 + }, + "F9": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 86.38, + "y": 29.24, + "z": 5.39 + }, + "G9": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 86.38, + "y": 20.24, + "z": 5.39 + }, + "H9": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 86.38, + "y": 11.24, + "z": 5.39 + }, + "A10": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 95.38, + "y": 74.24, + "z": 5.39 + }, + "B10": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 95.38, + "y": 65.24, + "z": 5.39 + }, + "C10": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 95.38, + "y": 56.24, + "z": 5.39 + }, + "D10": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 95.38, + "y": 47.24, + "z": 5.39 + }, + "E10": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 95.38, + "y": 38.24, + "z": 5.39 + }, + "F10": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 95.38, + "y": 29.24, + "z": 5.39 + }, + "G10": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 95.38, + "y": 20.24, + "z": 5.39 + }, + "H10": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 95.38, + "y": 11.24, + "z": 5.39 + }, + "A11": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 104.38, + "y": 74.24, + "z": 5.39 + }, + "B11": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 104.38, + "y": 65.24, + "z": 5.39 + }, + "C11": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 104.38, + "y": 56.24, + "z": 5.39 + }, + "D11": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 104.38, + "y": 47.24, + "z": 5.39 + }, + "E11": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 104.38, + "y": 38.24, + "z": 5.39 + }, + "F11": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 104.38, + "y": 29.24, + "z": 5.39 + }, + "G11": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 104.38, + "y": 20.24, + "z": 5.39 + }, + "H11": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 104.38, + "y": 11.24, + "z": 5.39 + }, + "A12": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 113.38, + "y": 74.24, + "z": 5.39 + }, + "B12": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 113.38, + "y": 65.24, + "z": 5.39 + }, + "C12": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 113.38, + "y": 56.24, + "z": 5.39 + }, + "D12": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 113.38, + "y": 47.24, + "z": 5.39 + }, + "E12": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 113.38, + "y": 38.24, + "z": 5.39 + }, + "F12": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 113.38, + "y": 29.24, + "z": 5.39 + }, + "G12": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 113.38, + "y": 20.24, + "z": 5.39 + }, + "H12": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 113.38, + "y": 11.24, + "z": 5.39 + } + }, + "groups": [ + { + "metadata": {}, + "wells": [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1", + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2", + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3", + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4", + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5", + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6", + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7", + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8", + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9", + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10", + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11", + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ] + } + ], + "parameters": { + "format": "96Standard", + "isTiprack": true, + "tipLength": 59.3, + "tipOverlap": 7.47, + "isMagneticModuleCompatible": false, + "loadName": "opentrons_96_tiprack_300ul" + }, + "namespace": "opentrons", + "version": 1, + "schemaVersion": 2, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + } + }, + "opentrons/opentrons_1_trash_1100ml_fixed/1": { + "ordering": [ + [ + "A1" + ] + ], + "metadata": { + "displayCategory": "trash", + "displayVolumeUnits": "mL", + "displayName": "Opentrons Fixed Trash", + "tags": [] + }, + "schemaVersion": 2, + "version": 1, + "namespace": "opentrons", + "dimensions": { + "xDimension": 172.86, + "yDimension": 165.86, + "zDimension": 82 + }, + "parameters": { + "format": "trash", + "isTiprack": false, + "loadName": "opentrons_1_trash_1100ml_fixed", + "isMagneticModuleCompatible": false, + "quirks": [ + "fixedTrash", + "centerMultichannelOnWells", + "touchTipDisabled" + ] + }, + "wells": { + "A1": { + "shape": "rectangular", + "yDimension": 165.67, + "xDimension": 107.11, + "totalLiquidVolume": 1100000, + "depth": 0, + "x": 82.84, + "y": 80, + "z": 82 + } + }, + "brand": { + "brand": "Opentrons" + }, + "groups": [ + { + "wells": [ + "A1" + ], + "metadata": {} + } + ], + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + } + }, + "opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1": { + "ordering": [ + [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1" + ], + [ + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2" + ], + [ + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3" + ], + [ + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4" + ], + [ + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5" + ], + [ + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6" + ], + [ + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7" + ], + [ + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8" + ], + [ + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9" + ], + [ + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10" + ], + [ + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11" + ], + [ + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ] + ], + "brand": { + "brand": "Opentrons", + "brandId": [], + "links": [] + }, + "metadata": { + "displayName": "Opentrons 96 Deep Well Adapter with NEST Deep Well Plate 2 mL", + "displayCategory": "aluminumBlock", + "displayVolumeUnits": "µL", + "tags": [] + }, + "dimensions": { + "xDimension": 127.6, + "yDimension": 85.3, + "zDimension": 42.25 + }, + "wells": { + "A1": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 14.3, + "y": 74.15, + "z": 4.25 + }, + "B1": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 14.3, + "y": 65.15, + "z": 4.25 + }, + "C1": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 14.3, + "y": 56.15, + "z": 4.25 + }, + "D1": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 14.3, + "y": 47.15, + "z": 4.25 + }, + "E1": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 14.3, + "y": 38.15, + "z": 4.25 + }, + "F1": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 14.3, + "y": 29.15, + "z": 4.25 + }, + "G1": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 14.3, + "y": 20.15, + "z": 4.25 + }, + "H1": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 14.3, + "y": 11.15, + "z": 4.25 + }, + "A2": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 23.3, + "y": 74.15, + "z": 4.25 + }, + "B2": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 23.3, + "y": 65.15, + "z": 4.25 + }, + "C2": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 23.3, + "y": 56.15, + "z": 4.25 + }, + "D2": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 23.3, + "y": 47.15, + "z": 4.25 + }, + "E2": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 23.3, + "y": 38.15, + "z": 4.25 + }, + "F2": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 23.3, + "y": 29.15, + "z": 4.25 + }, + "G2": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 23.3, + "y": 20.15, + "z": 4.25 + }, + "H2": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 23.3, + "y": 11.15, + "z": 4.25 + }, + "A3": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 32.3, + "y": 74.15, + "z": 4.25 + }, + "B3": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 32.3, + "y": 65.15, + "z": 4.25 + }, + "C3": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 32.3, + "y": 56.15, + "z": 4.25 + }, + "D3": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 32.3, + "y": 47.15, + "z": 4.25 + }, + "E3": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 32.3, + "y": 38.15, + "z": 4.25 + }, + "F3": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 32.3, + "y": 29.15, + "z": 4.25 + }, + "G3": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 32.3, + "y": 20.15, + "z": 4.25 + }, + "H3": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 32.3, + "y": 11.15, + "z": 4.25 + }, + "A4": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 41.3, + "y": 74.15, + "z": 4.25 + }, + "B4": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 41.3, + "y": 65.15, + "z": 4.25 + }, + "C4": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 41.3, + "y": 56.15, + "z": 4.25 + }, + "D4": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 41.3, + "y": 47.15, + "z": 4.25 + }, + "E4": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 41.3, + "y": 38.15, + "z": 4.25 + }, + "F4": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 41.3, + "y": 29.15, + "z": 4.25 + }, + "G4": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 41.3, + "y": 20.15, + "z": 4.25 + }, + "H4": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 41.3, + "y": 11.15, + "z": 4.25 + }, + "A5": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 50.3, + "y": 74.15, + "z": 4.25 + }, + "B5": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 50.3, + "y": 65.15, + "z": 4.25 + }, + "C5": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 50.3, + "y": 56.15, + "z": 4.25 + }, + "D5": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 50.3, + "y": 47.15, + "z": 4.25 + }, + "E5": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 50.3, + "y": 38.15, + "z": 4.25 + }, + "F5": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 50.3, + "y": 29.15, + "z": 4.25 + }, + "G5": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 50.3, + "y": 20.15, + "z": 4.25 + }, + "H5": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 50.3, + "y": 11.15, + "z": 4.25 + }, + "A6": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 59.3, + "y": 74.15, + "z": 4.25 + }, + "B6": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 59.3, + "y": 65.15, + "z": 4.25 + }, + "C6": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 59.3, + "y": 56.15, + "z": 4.25 + }, + "D6": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 59.3, + "y": 47.15, + "z": 4.25 + }, + "E6": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 59.3, + "y": 38.15, + "z": 4.25 + }, + "F6": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 59.3, + "y": 29.15, + "z": 4.25 + }, + "G6": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 59.3, + "y": 20.15, + "z": 4.25 + }, + "H6": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 59.3, + "y": 11.15, + "z": 4.25 + }, + "A7": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 68.3, + "y": 74.15, + "z": 4.25 + }, + "B7": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 68.3, + "y": 65.15, + "z": 4.25 + }, + "C7": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 68.3, + "y": 56.15, + "z": 4.25 + }, + "D7": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 68.3, + "y": 47.15, + "z": 4.25 + }, + "E7": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 68.3, + "y": 38.15, + "z": 4.25 + }, + "F7": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 68.3, + "y": 29.15, + "z": 4.25 + }, + "G7": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 68.3, + "y": 20.15, + "z": 4.25 + }, + "H7": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 68.3, + "y": 11.15, + "z": 4.25 + }, + "A8": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 77.3, + "y": 74.15, + "z": 4.25 + }, + "B8": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 77.3, + "y": 65.15, + "z": 4.25 + }, + "C8": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 77.3, + "y": 56.15, + "z": 4.25 + }, + "D8": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 77.3, + "y": 47.15, + "z": 4.25 + }, + "E8": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 77.3, + "y": 38.15, + "z": 4.25 + }, + "F8": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 77.3, + "y": 29.15, + "z": 4.25 + }, + "G8": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 77.3, + "y": 20.15, + "z": 4.25 + }, + "H8": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 77.3, + "y": 11.15, + "z": 4.25 + }, + "A9": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 86.3, + "y": 74.15, + "z": 4.25 + }, + "B9": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 86.3, + "y": 65.15, + "z": 4.25 + }, + "C9": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 86.3, + "y": 56.15, + "z": 4.25 + }, + "D9": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 86.3, + "y": 47.15, + "z": 4.25 + }, + "E9": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 86.3, + "y": 38.15, + "z": 4.25 + }, + "F9": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 86.3, + "y": 29.15, + "z": 4.25 + }, + "G9": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 86.3, + "y": 20.15, + "z": 4.25 + }, + "H9": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 86.3, + "y": 11.15, + "z": 4.25 + }, + "A10": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 95.3, + "y": 74.15, + "z": 4.25 + }, + "B10": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 95.3, + "y": 65.15, + "z": 4.25 + }, + "C10": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 95.3, + "y": 56.15, + "z": 4.25 + }, + "D10": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 95.3, + "y": 47.15, + "z": 4.25 + }, + "E10": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 95.3, + "y": 38.15, + "z": 4.25 + }, + "F10": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 95.3, + "y": 29.15, + "z": 4.25 + }, + "G10": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 95.3, + "y": 20.15, + "z": 4.25 + }, + "H10": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 95.3, + "y": 11.15, + "z": 4.25 + }, + "A11": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 104.3, + "y": 74.15, + "z": 4.25 + }, + "B11": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 104.3, + "y": 65.15, + "z": 4.25 + }, + "C11": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 104.3, + "y": 56.15, + "z": 4.25 + }, + "D11": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 104.3, + "y": 47.15, + "z": 4.25 + }, + "E11": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 104.3, + "y": 38.15, + "z": 4.25 + }, + "F11": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 104.3, + "y": 29.15, + "z": 4.25 + }, + "G11": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 104.3, + "y": 20.15, + "z": 4.25 + }, + "H11": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 104.3, + "y": 11.15, + "z": 4.25 + }, + "A12": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 113.3, + "y": 74.15, + "z": 4.25 + }, + "B12": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 113.3, + "y": 65.15, + "z": 4.25 + }, + "C12": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 113.3, + "y": 56.15, + "z": 4.25 + }, + "D12": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 113.3, + "y": 47.15, + "z": 4.25 + }, + "E12": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 113.3, + "y": 38.15, + "z": 4.25 + }, + "F12": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 113.3, + "y": 29.15, + "z": 4.25 + }, + "G12": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 113.3, + "y": 20.15, + "z": 4.25 + }, + "H12": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 113.3, + "y": 11.15, + "z": 4.25 + } + }, + "groups": [ + { + "metadata": { + "displayName": "NEST 96 Deepwell Plate 2mL", + "displayCategory": "wellPlate", + "wellBottomShape": "v" + }, + "brand": { + "brand": "NEST", + "brandId": [ + "503501", + "503001" + ], + "links": [ + "https://www.nest-biotech.com/deep-well-plates/59253726.html" + ] + }, + "wells": [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1", + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2", + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3", + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4", + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5", + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6", + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7", + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8", + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9", + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10", + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11", + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ] + } + ], + "parameters": { + "format": "96Standard", + "quirks": [], + "isTiprack": false, + "isMagneticModuleCompatible": false, + "loadName": "opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep" + }, + "namespace": "opentrons", + "version": 1, + "schemaVersion": 2, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + } + }, + "opentrons/armadillo_96_wellplate_200ul_pcr_full_skirt/1": { + "namespace": "opentrons", + "version": 1, + "schemaVersion": 2, + "parameters": { + "loadName": "armadillo_96_wellplate_200ul_pcr_full_skirt", + "format": "96Standard", + "isTiprack": false, + "isMagneticModuleCompatible": true + }, + "metadata": { + "displayName": "Armadillo 96 Well Plate 200 µL PCR Full Skirt", + "displayCategory": "wellPlate", + "displayVolumeUnits": "µL", + "tags": [] + }, + "brand": { + "brand": "Thermo Scientific", + "brandId": [ + "AB2396" + ], + "links": [ + "https://www.fishersci.com/shop/products/armadillo-96-well-pcr-plate-1/AB2396" + ] + }, + "dimensions": { + "xDimension": 127.76, + "yDimension": 85.48, + "zDimension": 16 + }, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + }, + "ordering": [ + [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1" + ], + [ + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2" + ], + [ + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3" + ], + [ + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4" + ], + [ + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5" + ], + [ + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6" + ], + [ + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7" + ], + [ + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8" + ], + [ + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9" + ], + [ + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10" + ], + [ + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11" + ], + [ + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ] + ], + "wells": { + "A1": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 14.38, + "y": 74.24, + "z": 1.05 + }, + "B1": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 14.38, + "y": 65.24, + "z": 1.05 + }, + "C1": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 14.38, + "y": 56.24, + "z": 1.05 + }, + "D1": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 14.38, + "y": 47.24, + "z": 1.05 + }, + "E1": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 14.38, + "y": 38.24, + "z": 1.05 + }, + "F1": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 14.38, + "y": 29.24, + "z": 1.05 + }, + "G1": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 14.38, + "y": 20.24, + "z": 1.05 + }, + "H1": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 14.38, + "y": 11.24, + "z": 1.05 + }, + "A2": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 23.38, + "y": 74.24, + "z": 1.05 + }, + "B2": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 23.38, + "y": 65.24, + "z": 1.05 + }, + "C2": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 23.38, + "y": 56.24, + "z": 1.05 + }, + "D2": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 23.38, + "y": 47.24, + "z": 1.05 + }, + "E2": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 23.38, + "y": 38.24, + "z": 1.05 + }, + "F2": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 23.38, + "y": 29.24, + "z": 1.05 + }, + "G2": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 23.38, + "y": 20.24, + "z": 1.05 + }, + "H2": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 23.38, + "y": 11.24, + "z": 1.05 + }, + "A3": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 32.38, + "y": 74.24, + "z": 1.05 + }, + "B3": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 32.38, + "y": 65.24, + "z": 1.05 + }, + "C3": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 32.38, + "y": 56.24, + "z": 1.05 + }, + "D3": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 32.38, + "y": 47.24, + "z": 1.05 + }, + "E3": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 32.38, + "y": 38.24, + "z": 1.05 + }, + "F3": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 32.38, + "y": 29.24, + "z": 1.05 + }, + "G3": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 32.38, + "y": 20.24, + "z": 1.05 + }, + "H3": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 32.38, + "y": 11.24, + "z": 1.05 + }, + "A4": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 41.38, + "y": 74.24, + "z": 1.05 + }, + "B4": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 41.38, + "y": 65.24, + "z": 1.05 + }, + "C4": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 41.38, + "y": 56.24, + "z": 1.05 + }, + "D4": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 41.38, + "y": 47.24, + "z": 1.05 + }, + "E4": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 41.38, + "y": 38.24, + "z": 1.05 + }, + "F4": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 41.38, + "y": 29.24, + "z": 1.05 + }, + "G4": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 41.38, + "y": 20.24, + "z": 1.05 + }, + "H4": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 41.38, + "y": 11.24, + "z": 1.05 + }, + "A5": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 50.38, + "y": 74.24, + "z": 1.05 + }, + "B5": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 50.38, + "y": 65.24, + "z": 1.05 + }, + "C5": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 50.38, + "y": 56.24, + "z": 1.05 + }, + "D5": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 50.38, + "y": 47.24, + "z": 1.05 + }, + "E5": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 50.38, + "y": 38.24, + "z": 1.05 + }, + "F5": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 50.38, + "y": 29.24, + "z": 1.05 + }, + "G5": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 50.38, + "y": 20.24, + "z": 1.05 + }, + "H5": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 50.38, + "y": 11.24, + "z": 1.05 + }, + "A6": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 59.38, + "y": 74.24, + "z": 1.05 + }, + "B6": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 59.38, + "y": 65.24, + "z": 1.05 + }, + "C6": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 59.38, + "y": 56.24, + "z": 1.05 + }, + "D6": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 59.38, + "y": 47.24, + "z": 1.05 + }, + "E6": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 59.38, + "y": 38.24, + "z": 1.05 + }, + "F6": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 59.38, + "y": 29.24, + "z": 1.05 + }, + "G6": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 59.38, + "y": 20.24, + "z": 1.05 + }, + "H6": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 59.38, + "y": 11.24, + "z": 1.05 + }, + "A7": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 68.38, + "y": 74.24, + "z": 1.05 + }, + "B7": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 68.38, + "y": 65.24, + "z": 1.05 + }, + "C7": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 68.38, + "y": 56.24, + "z": 1.05 + }, + "D7": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 68.38, + "y": 47.24, + "z": 1.05 + }, + "E7": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 68.38, + "y": 38.24, + "z": 1.05 + }, + "F7": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 68.38, + "y": 29.24, + "z": 1.05 + }, + "G7": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 68.38, + "y": 20.24, + "z": 1.05 + }, + "H7": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 68.38, + "y": 11.24, + "z": 1.05 + }, + "A8": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 77.38, + "y": 74.24, + "z": 1.05 + }, + "B8": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 77.38, + "y": 65.24, + "z": 1.05 + }, + "C8": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 77.38, + "y": 56.24, + "z": 1.05 + }, + "D8": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 77.38, + "y": 47.24, + "z": 1.05 + }, + "E8": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 77.38, + "y": 38.24, + "z": 1.05 + }, + "F8": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 77.38, + "y": 29.24, + "z": 1.05 + }, + "G8": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 77.38, + "y": 20.24, + "z": 1.05 + }, + "H8": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 77.38, + "y": 11.24, + "z": 1.05 + }, + "A9": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 86.38, + "y": 74.24, + "z": 1.05 + }, + "B9": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 86.38, + "y": 65.24, + "z": 1.05 + }, + "C9": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 86.38, + "y": 56.24, + "z": 1.05 + }, + "D9": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 86.38, + "y": 47.24, + "z": 1.05 + }, + "E9": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 86.38, + "y": 38.24, + "z": 1.05 + }, + "F9": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 86.38, + "y": 29.24, + "z": 1.05 + }, + "G9": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 86.38, + "y": 20.24, + "z": 1.05 + }, + "H9": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 86.38, + "y": 11.24, + "z": 1.05 + }, + "A10": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 95.38, + "y": 74.24, + "z": 1.05 + }, + "B10": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 95.38, + "y": 65.24, + "z": 1.05 + }, + "C10": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 95.38, + "y": 56.24, + "z": 1.05 + }, + "D10": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 95.38, + "y": 47.24, + "z": 1.05 + }, + "E10": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 95.38, + "y": 38.24, + "z": 1.05 + }, + "F10": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 95.38, + "y": 29.24, + "z": 1.05 + }, + "G10": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 95.38, + "y": 20.24, + "z": 1.05 + }, + "H10": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 95.38, + "y": 11.24, + "z": 1.05 + }, + "A11": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 104.38, + "y": 74.24, + "z": 1.05 + }, + "B11": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 104.38, + "y": 65.24, + "z": 1.05 + }, + "C11": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 104.38, + "y": 56.24, + "z": 1.05 + }, + "D11": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 104.38, + "y": 47.24, + "z": 1.05 + }, + "E11": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 104.38, + "y": 38.24, + "z": 1.05 + }, + "F11": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 104.38, + "y": 29.24, + "z": 1.05 + }, + "G11": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 104.38, + "y": 20.24, + "z": 1.05 + }, + "H11": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 104.38, + "y": 11.24, + "z": 1.05 + }, + "A12": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 113.38, + "y": 74.24, + "z": 1.05 + }, + "B12": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 113.38, + "y": 65.24, + "z": 1.05 + }, + "C12": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 113.38, + "y": 56.24, + "z": 1.05 + }, + "D12": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 113.38, + "y": 47.24, + "z": 1.05 + }, + "E12": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 113.38, + "y": 38.24, + "z": 1.05 + }, + "F12": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 113.38, + "y": 29.24, + "z": 1.05 + }, + "G12": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 113.38, + "y": 20.24, + "z": 1.05 + }, + "H12": { + "depth": 14.95, + "totalLiquidVolume": 200, + "shape": "circular", + "diameter": 5.5, + "x": 113.38, + "y": 11.24, + "z": 1.05 + } + }, + "groups": [ + { + "metadata": { + "wellBottomShape": "v" + }, + "wells": [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1", + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2", + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3", + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4", + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5", + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6", + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7", + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8", + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9", + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10", + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11", + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ] + } + ] + } + }, + "$otSharedSchema": "#/protocol/schemas/6", + "schemaVersion": 6, + "modules": { + "b8a48baa-1ee2-448d-8680-c7126843cbe4:heaterShakerModuleType": { + "model": "heaterShakerModuleV1" + } + }, + "commands": [ + { + "key": "371f4a86-b9a5-4bc0-8bdd-d28460087c31", + "commandType": "loadPipette", + "params": { + "pipetteId": "d7e73681-8957-4063-8ce1-38c12373ec39", + "mount": "left" + } + }, + { + "key": "00c0d791-6167-4a8b-8822-0482a6229976", + "commandType": "loadPipette", + "params": { + "pipetteId": "f5937b23-677d-4cff-bc10-224cf022858c", + "mount": "right" + } + }, + { + "key": "e3a5093f-bfb7-433b-a064-05de0c322c35", + "commandType": "loadModule", + "params": { + "moduleId": "b8a48baa-1ee2-448d-8680-c7126843cbe4:heaterShakerModuleType", + "location": { + "slotName": "1" + } + } + }, + { + "key": "1f08132e-50c9-457b-b543-1d3318c5d075", + "commandType": "loadLabware", + "params": { + "labwareId": "1a8aeb5d-d5df-41b2-a794-ff967118e126:opentrons/opentrons_96_tiprack_300ul/1", + "location": { + "slotName": "2" + } + } + }, + { + "key": "f6ad95f9-6d54-453e-8630-50ee166deb5a", + "commandType": "loadLabware", + "params": { + "labwareId": "59b6af9f-7b2f-4007-a5ef-ef60d38939dc:opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1", + "location": { + "moduleId": "b8a48baa-1ee2-448d-8680-c7126843cbe4:heaterShakerModuleType" + } + } + }, + { + "key": "83b274d2-cbf1-4913-95dd-2c29e196983c", + "commandType": "loadLabware", + "params": { + "labwareId": "3268de61-0657-4a48-8e63-0c3b4bf502a1:opentrons/opentrons_96_tiprack_300ul/1", + "location": { + "slotName": "4" + } + } + }, + { + "key": "10a1df55-87a4-4eb3-ba1c-4e9b6e4ed3e5", + "commandType": "loadLabware", + "params": { + "labwareId": "dbed30a1-d5d7-48b7-82f6-284a20b06118:opentrons/armadillo_96_wellplate_200ul_pcr_full_skirt/1", + "location": { + "slotName": "5" + } + } + }, + { + "commandType": "loadLiquid", + "key": "99f4bd4a-9385-45cf-b57c-55a619e9b961", + "params": { + "liquidId": "0", + "labwareId": "dbed30a1-d5d7-48b7-82f6-284a20b06118:opentrons/armadillo_96_wellplate_200ul_pcr_full_skirt/1", + "volumeByWell": { + "A1": 100, + "B1": 100, + "C1": 100, + "D1": 100, + "E1": 100, + "F1": 100, + "G1": 100, + "H1": 100, + "A2": 100, + "B2": 100, + "C2": 100, + "D2": 100, + "E2": 100, + "F2": 100, + "G2": 100, + "H2": 100, + "A3": 100, + "B3": 100, + "C3": 100, + "D3": 100, + "E3": 100, + "F3": 100, + "G3": 100, + "H3": 100 + } + } + }, + { + "commandType": "heaterShaker/closeLabwareLatch", + "key": "e5e36a96-61c3-4d73-98a7-17aeb667b727", + "params": { + "moduleId": "b8a48baa-1ee2-448d-8680-c7126843cbe4:heaterShakerModuleType" + } + }, + { + "commandType": "heaterShaker/deactivateHeater", + "key": "fe2e39c4-5245-465a-8df8-33096913a07d", + "params": { + "moduleId": "b8a48baa-1ee2-448d-8680-c7126843cbe4:heaterShakerModuleType" + } + }, + { + "commandType": "heaterShaker/deactivateShaker", + "key": "b214ab6f-85af-46be-85ea-ec7fbde9cf15", + "params": { + "moduleId": "b8a48baa-1ee2-448d-8680-c7126843cbe4:heaterShakerModuleType" + } + } + ] +} \ No newline at end of file diff --git a/app-testing/files/protocols/OT2_X_v6_P300M_P20S_HS_MM_TM_TC_AllMods.json b/app-testing/files/protocols/OT2_X_v6_P300M_P20S_HS_MM_TM_TC_AllMods.json new file mode 100644 index 00000000000..f478860716c --- /dev/null +++ b/app-testing/files/protocols/OT2_X_v6_P300M_P20S_HS_MM_TM_TC_AllMods.json @@ -0,0 +1,6226 @@ +{ + "metadata": { + "protocolName": "All mods", + "author": "", + "description": "", + "created": 1660661146739, + "lastModified": 1660661894787, + "category": null, + "subcategory": null, + "tags": [] + }, + "designerApplication": { + "name": "opentrons/protocol-designer", + "version": "6.0.0", + "data": { + "_internalAppBuildDate": "Mon, 08 Aug 2022 21:31:42 GMT", + "defaultValues": { + "aspirate_mmFromBottom": 1, + "dispense_mmFromBottom": 0.5, + "touchTip_mmFromTop": -1, + "blowout_mmFromTop": 0 + }, + "pipetteTiprackAssignments": { + "9467efbc-2ad4-40eb-bc05-91c78fd48be2": "opentrons/opentrons_96_tiprack_300ul/1", + "1b766d4d-ba31-42cc-a49a-73e9d8c67aca": "opentrons/opentrons_96_tiprack_300ul/1" + }, + "dismissedWarnings": { + "form": {}, + "timeline": {} + }, + "ingredients": { + "0": { + "name": "L1", + "displayColor": "#b925ff", + "description": null, + "serialize": false, + "liquidGroupId": "0" + }, + "1": { + "name": "L2", + "displayColor": "#ffd600", + "description": null, + "serialize": false, + "liquidGroupId": "1" + } + }, + "ingredLocations": { + "bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1": { + "A1": { + "0": { + "volume": 29000 + } + } + }, + "01ab8b91-996c-41a2-a11e-57719913979e:opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1": { + "A1": { + "1": { + "volume": 300 + } + }, + "B1": { + "1": { + "volume": 300 + } + }, + "C1": { + "1": { + "volume": 300 + } + }, + "D1": { + "1": { + "volume": 300 + } + }, + "A2": { + "1": { + "volume": 300 + } + }, + "B2": { + "1": { + "volume": 300 + } + }, + "C2": { + "1": { + "volume": 300 + } + }, + "D2": { + "1": { + "volume": 300 + } + } + }, + "0d460f8a-2163-4eb7-8f48-5c382604971a:opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1": { + "A1": { + "1": { + "volume": 20 + } + }, + "B1": { + "1": { + "volume": 20 + } + }, + "C1": { + "1": { + "volume": 20 + } + }, + "D1": { + "1": { + "volume": 20 + } + }, + "E1": { + "1": { + "volume": 20 + } + }, + "F1": { + "1": { + "volume": 20 + } + }, + "G1": { + "1": { + "volume": 20 + } + }, + "H1": { + "1": { + "volume": 20 + } + }, + "A2": { + "1": { + "volume": 20 + } + }, + "B2": { + "1": { + "volume": 20 + } + }, + "C2": { + "1": { + "volume": 20 + } + }, + "D2": { + "1": { + "volume": 20 + } + }, + "E2": { + "1": { + "volume": 20 + } + }, + "F2": { + "1": { + "volume": 20 + } + }, + "G2": { + "1": { + "volume": 20 + } + }, + "H2": { + "1": { + "volume": 20 + } + }, + "A3": { + "1": { + "volume": 20 + } + }, + "B3": { + "1": { + "volume": 20 + } + }, + "C3": { + "1": { + "volume": 20 + } + }, + "D3": { + "1": { + "volume": 20 + } + }, + "E3": { + "1": { + "volume": 20 + } + }, + "F3": { + "1": { + "volume": 20 + } + }, + "G3": { + "1": { + "volume": 20 + } + }, + "H3": { + "1": { + "volume": 20 + } + } + }, + "111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1": { + "A1": { + "1": { + "volume": 100 + } + }, + "B1": { + "1": { + "volume": 100 + } + }, + "C1": { + "1": { + "volume": 100 + } + }, + "D1": { + "1": { + "volume": 100 + } + }, + "E1": { + "1": { + "volume": 100 + } + }, + "F1": { + "1": { + "volume": 100 + } + }, + "G1": { + "1": { + "volume": 100 + } + }, + "H1": { + "1": { + "volume": 100 + } + }, + "A2": { + "1": { + "volume": 100 + } + }, + "B2": { + "1": { + "volume": 100 + } + }, + "C2": { + "1": { + "volume": 100 + } + }, + "D2": { + "1": { + "volume": 100 + } + }, + "E2": { + "1": { + "volume": 100 + } + }, + "F2": { + "1": { + "volume": 100 + } + }, + "G2": { + "1": { + "volume": 100 + } + }, + "H2": { + "1": { + "volume": 100 + } + }, + "A3": { + "1": { + "volume": 100 + } + }, + "B3": { + "1": { + "volume": 100 + } + }, + "C3": { + "1": { + "volume": 100 + } + }, + "D3": { + "1": { + "volume": 100 + } + }, + "E3": { + "1": { + "volume": 100 + } + }, + "F3": { + "1": { + "volume": 100 + } + }, + "G3": { + "1": { + "volume": 100 + } + }, + "H3": { + "1": { + "volume": 100 + } + }, + "A4": { + "1": { + "volume": 100 + } + }, + "B4": { + "1": { + "volume": 100 + } + }, + "C4": { + "1": { + "volume": 100 + } + }, + "D4": { + "1": { + "volume": 100 + } + }, + "E4": { + "1": { + "volume": 100 + } + }, + "F4": { + "1": { + "volume": 100 + } + }, + "G4": { + "1": { + "volume": 100 + } + }, + "H4": { + "1": { + "volume": 100 + } + }, + "A5": { + "1": { + "volume": 100 + } + }, + "B5": { + "1": { + "volume": 100 + } + }, + "C5": { + "1": { + "volume": 100 + } + }, + "D5": { + "1": { + "volume": 100 + } + }, + "E5": { + "1": { + "volume": 100 + } + }, + "F5": { + "1": { + "volume": 100 + } + }, + "G5": { + "1": { + "volume": 100 + } + }, + "H5": { + "1": { + "volume": 100 + } + }, + "A6": { + "1": { + "volume": 100 + } + }, + "B6": { + "1": { + "volume": 100 + } + }, + "C6": { + "1": { + "volume": 100 + } + }, + "D6": { + "1": { + "volume": 100 + } + }, + "E6": { + "1": { + "volume": 100 + } + }, + "F6": { + "1": { + "volume": 100 + } + }, + "G6": { + "1": { + "volume": 100 + } + }, + "H6": { + "1": { + "volume": 100 + } + } + }, + "32e39cda-1d1d-4e0d-b933-b94cf464e29a:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1": { + "A1": { + "1": { + "volume": 100 + } + }, + "B1": { + "1": { + "volume": 100 + } + }, + "C1": { + "1": { + "volume": 100 + } + }, + "D1": { + "1": { + "volume": 100 + } + }, + "E1": { + "1": { + "volume": 100 + } + }, + "F1": { + "1": { + "volume": 100 + } + }, + "G1": { + "1": { + "volume": 100 + } + }, + "H1": { + "1": { + "volume": 100 + } + }, + "A2": { + "1": { + "volume": 100 + } + }, + "B2": { + "1": { + "volume": 100 + } + }, + "C2": { + "1": { + "volume": 100 + } + }, + "D2": { + "1": { + "volume": 100 + } + }, + "E2": { + "1": { + "volume": 100 + } + }, + "F2": { + "1": { + "volume": 100 + } + }, + "G2": { + "1": { + "volume": 100 + } + }, + "H2": { + "1": { + "volume": 100 + } + }, + "A3": { + "1": { + "volume": 100 + } + }, + "B3": { + "1": { + "volume": 100 + } + }, + "C3": { + "1": { + "volume": 100 + } + }, + "D3": { + "1": { + "volume": 100 + } + }, + "E3": { + "1": { + "volume": 100 + } + }, + "F3": { + "1": { + "volume": 100 + } + }, + "G3": { + "1": { + "volume": 100 + } + }, + "H3": { + "1": { + "volume": 100 + } + }, + "A4": { + "1": { + "volume": 100 + } + }, + "B4": { + "1": { + "volume": 100 + } + }, + "C4": { + "1": { + "volume": 100 + } + }, + "D4": { + "1": { + "volume": 100 + } + }, + "E4": { + "1": { + "volume": 100 + } + }, + "F4": { + "1": { + "volume": 100 + } + }, + "G4": { + "1": { + "volume": 100 + } + }, + "H4": { + "1": { + "volume": 100 + } + }, + "A5": { + "1": { + "volume": 100 + } + }, + "B5": { + "1": { + "volume": 100 + } + }, + "C5": { + "1": { + "volume": 100 + } + }, + "D5": { + "1": { + "volume": 100 + } + }, + "E5": { + "1": { + "volume": 100 + } + }, + "F5": { + "1": { + "volume": 100 + } + }, + "G5": { + "1": { + "volume": 100 + } + }, + "H5": { + "1": { + "volume": 100 + } + }, + "A6": { + "1": { + "volume": 100 + } + }, + "B6": { + "1": { + "volume": 100 + } + }, + "C6": { + "1": { + "volume": 100 + } + }, + "D6": { + "1": { + "volume": 100 + } + }, + "E6": { + "1": { + "volume": 100 + } + }, + "F6": { + "1": { + "volume": 100 + } + }, + "G6": { + "1": { + "volume": 100 + } + }, + "H6": { + "1": { + "volume": 100 + } + } + } + }, + "savedStepForms": { + "__INITIAL_DECK_SETUP_STEP__": { + "stepType": "manualIntervention", + "id": "__INITIAL_DECK_SETUP_STEP__", + "labwareLocationUpdate": { + "fixedTrash": "12", + "a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1": "5", + "0d460f8a-2163-4eb7-8f48-5c382604971a:opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1": "5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType", + "01ab8b91-996c-41a2-a11e-57719913979e:opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1": "b5df8f5c-9fc5-4d45-98c2-0ce6bd218fda:temperatureModuleType", + "32e39cda-1d1d-4e0d-b933-b94cf464e29a:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1": "8d4683d0-7a88-4b33-9363-bd3894a71f9a:magneticModuleType", + "111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1": "a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType", + "bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1": "6" + }, + "pipetteLocationUpdate": { + "9467efbc-2ad4-40eb-bc05-91c78fd48be2": "left", + "1b766d4d-ba31-42cc-a49a-73e9d8c67aca": "right" + }, + "moduleLocationUpdate": { + "5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType": "1", + "8d4683d0-7a88-4b33-9363-bd3894a71f9a:magneticModuleType": "9", + "b5df8f5c-9fc5-4d45-98c2-0ce6bd218fda:temperatureModuleType": "3", + "a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType": "span7_8_10_11" + } + }, + "8506adb8-05bc-49cd-a159-f1af3623012f": { + "id": "8506adb8-05bc-49cd-a159-f1af3623012f", + "stepType": "heaterShaker", + "stepName": "heater-shaker", + "stepDetails": "", + "moduleId": "5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType", + "setHeaterShakerTemperature": null, + "targetHeaterShakerTemperature": null, + "targetSpeed": null, + "setShake": null, + "latchOpen": false, + "heaterShakerSetTimer": null, + "heaterShakerTimerMinutes": null, + "heaterShakerTimerSeconds": null + }, + "28f5eb49-8cac-4658-aa04-2021277f6026": { + "id": "28f5eb49-8cac-4658-aa04-2021277f6026", + "stepType": "thermocycler", + "stepName": "thermocycler", + "stepDetails": "", + "thermocyclerFormType": "thermocyclerState", + "moduleId": "a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType", + "blockIsActive": false, + "blockTargetTemp": null, + "lidIsActive": false, + "lidTargetTemp": null, + "lidOpen": true, + "profileVolume": null, + "profileTargetLidTemp": null, + "orderedProfileItems": [], + "profileItemsById": {}, + "blockIsActiveHold": false, + "blockTargetTempHold": null, + "lidIsActiveHold": false, + "lidTargetTempHold": null, + "lidOpenHold": null + }, + "5fe8dbb8-ccae-4ca8-8015-7d53fd182cb0": { + "id": "5fe8dbb8-ccae-4ca8-8015-7d53fd182cb0", + "stepType": "moveLiquid", + "stepName": "transfer", + "stepDetails": "", + "pipette": "9467efbc-2ad4-40eb-bc05-91c78fd48be2", + "volume": "20", + "changeTip": "once", + "path": "single", + "aspirate_wells_grouped": false, + "aspirate_flowRate": null, + "aspirate_labware": "bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1", + "aspirate_wells": [ + "A1" + ], + "aspirate_wellOrder_first": "t2b", + "aspirate_wellOrder_second": "l2r", + "aspirate_mix_checkbox": false, + "aspirate_mix_times": null, + "aspirate_mix_volume": null, + "aspirate_mmFromBottom": null, + "aspirate_touchTip_checkbox": false, + "aspirate_touchTip_mmFromBottom": null, + "dispense_flowRate": null, + "dispense_labware": "0d460f8a-2163-4eb7-8f48-5c382604971a:opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1", + "dispense_wells": [ + "A4" + ], + "dispense_wellOrder_first": "t2b", + "dispense_wellOrder_second": "l2r", + "dispense_mix_checkbox": false, + "dispense_mix_times": null, + "dispense_mix_volume": null, + "dispense_mmFromBottom": null, + "dispense_touchTip_checkbox": false, + "dispense_touchTip_mmFromBottom": null, + "disposalVolume_checkbox": true, + "disposalVolume_volume": "20", + "blowout_checkbox": false, + "blowout_location": "fixedTrash", + "preWetTip": false, + "aspirate_airGap_checkbox": false, + "aspirate_airGap_volume": "20", + "aspirate_delay_checkbox": false, + "aspirate_delay_mmFromBottom": null, + "aspirate_delay_seconds": "1", + "dispense_airGap_checkbox": false, + "dispense_airGap_volume": "20", + "dispense_delay_checkbox": false, + "dispense_delay_seconds": "1", + "dispense_delay_mmFromBottom": null + }, + "ba4d8515-524b-41cd-9953-72fe308e69f0": { + "id": "ba4d8515-524b-41cd-9953-72fe308e69f0", + "stepType": "moveLiquid", + "stepName": "transfer", + "stepDetails": "", + "pipette": "9467efbc-2ad4-40eb-bc05-91c78fd48be2", + "volume": "20", + "changeTip": "always", + "path": "single", + "aspirate_wells_grouped": false, + "aspirate_flowRate": null, + "aspirate_labware": "bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1", + "aspirate_wells": [ + "A1" + ], + "aspirate_wellOrder_first": "t2b", + "aspirate_wellOrder_second": "l2r", + "aspirate_mix_checkbox": false, + "aspirate_mix_times": null, + "aspirate_mix_volume": null, + "aspirate_mmFromBottom": null, + "aspirate_touchTip_checkbox": false, + "aspirate_touchTip_mmFromBottom": null, + "dispense_flowRate": null, + "dispense_labware": "32e39cda-1d1d-4e0d-b933-b94cf464e29a:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1", + "dispense_wells": [ + "A7" + ], + "dispense_wellOrder_first": "t2b", + "dispense_wellOrder_second": "l2r", + "dispense_mix_checkbox": false, + "dispense_mix_times": null, + "dispense_mix_volume": null, + "dispense_mmFromBottom": null, + "dispense_touchTip_checkbox": false, + "dispense_touchTip_mmFromBottom": null, + "disposalVolume_checkbox": true, + "disposalVolume_volume": "20", + "blowout_checkbox": false, + "blowout_location": "fixedTrash", + "preWetTip": false, + "aspirate_airGap_checkbox": false, + "aspirate_airGap_volume": "20", + "aspirate_delay_checkbox": false, + "aspirate_delay_mmFromBottom": null, + "aspirate_delay_seconds": "1", + "dispense_airGap_checkbox": false, + "dispense_airGap_volume": "20", + "dispense_delay_checkbox": false, + "dispense_delay_seconds": "1", + "dispense_delay_mmFromBottom": null + }, + "6dff24c4-13ad-4a0e-9eb8-66048f96ca0c": { + "id": "6dff24c4-13ad-4a0e-9eb8-66048f96ca0c", + "stepType": "moveLiquid", + "stepName": "transfer", + "stepDetails": "", + "pipette": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "volume": "25", + "changeTip": "always", + "path": "single", + "aspirate_wells_grouped": false, + "aspirate_flowRate": null, + "aspirate_labware": "bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1", + "aspirate_wells": [ + "A1" + ], + "aspirate_wellOrder_first": "t2b", + "aspirate_wellOrder_second": "l2r", + "aspirate_mix_checkbox": false, + "aspirate_mix_times": null, + "aspirate_mix_volume": null, + "aspirate_mmFromBottom": null, + "aspirate_touchTip_checkbox": false, + "aspirate_touchTip_mmFromBottom": null, + "dispense_flowRate": null, + "dispense_labware": "01ab8b91-996c-41a2-a11e-57719913979e:opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1", + "dispense_wells": [ + "A3", + "B3", + "C3", + "D3" + ], + "dispense_wellOrder_first": "t2b", + "dispense_wellOrder_second": "l2r", + "dispense_mix_checkbox": false, + "dispense_mix_times": null, + "dispense_mix_volume": null, + "dispense_mmFromBottom": null, + "dispense_touchTip_checkbox": false, + "dispense_touchTip_mmFromBottom": null, + "disposalVolume_checkbox": true, + "disposalVolume_volume": "20", + "blowout_checkbox": false, + "blowout_location": "fixedTrash", + "preWetTip": false, + "aspirate_airGap_checkbox": false, + "aspirate_airGap_volume": "20", + "aspirate_delay_checkbox": false, + "aspirate_delay_mmFromBottom": null, + "aspirate_delay_seconds": "1", + "dispense_airGap_checkbox": false, + "dispense_airGap_volume": "20", + "dispense_delay_checkbox": false, + "dispense_delay_seconds": "1", + "dispense_delay_mmFromBottom": null + }, + "1e9d8a92-e791-452b-9275-638ae8206dda": { + "id": "1e9d8a92-e791-452b-9275-638ae8206dda", + "stepType": "moveLiquid", + "stepName": "transfer", + "stepDetails": "", + "pipette": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "volume": "22", + "changeTip": "always", + "path": "single", + "aspirate_wells_grouped": false, + "aspirate_flowRate": null, + "aspirate_labware": "bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1", + "aspirate_wells": [ + "A1" + ], + "aspirate_wellOrder_first": "t2b", + "aspirate_wellOrder_second": "l2r", + "aspirate_mix_checkbox": false, + "aspirate_mix_times": null, + "aspirate_mix_volume": null, + "aspirate_mmFromBottom": null, + "aspirate_touchTip_checkbox": false, + "aspirate_touchTip_mmFromBottom": null, + "dispense_flowRate": null, + "dispense_labware": "111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1", + "dispense_wells": [ + "A7", + "B7", + "C7", + "A8", + "B8", + "C8" + ], + "dispense_wellOrder_first": "t2b", + "dispense_wellOrder_second": "l2r", + "dispense_mix_checkbox": false, + "dispense_mix_times": null, + "dispense_mix_volume": null, + "dispense_mmFromBottom": null, + "dispense_touchTip_checkbox": false, + "dispense_touchTip_mmFromBottom": null, + "disposalVolume_checkbox": true, + "disposalVolume_volume": "20", + "blowout_checkbox": false, + "blowout_location": "fixedTrash", + "preWetTip": false, + "aspirate_airGap_checkbox": false, + "aspirate_airGap_volume": "20", + "aspirate_delay_checkbox": false, + "aspirate_delay_mmFromBottom": null, + "aspirate_delay_seconds": "1", + "dispense_airGap_checkbox": false, + "dispense_airGap_volume": "20", + "dispense_delay_checkbox": false, + "dispense_delay_seconds": "1", + "dispense_delay_mmFromBottom": null + }, + "ea9a9a34-6d2d-46f1-b10b-fb5d8d28d827": { + "id": "ea9a9a34-6d2d-46f1-b10b-fb5d8d28d827", + "stepType": "thermocycler", + "stepName": "thermocycler", + "stepDetails": "", + "thermocyclerFormType": "thermocyclerState", + "moduleId": "a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType", + "blockIsActive": true, + "blockTargetTemp": "55", + "lidIsActive": true, + "lidTargetTemp": "50", + "lidOpen": false, + "profileVolume": null, + "profileTargetLidTemp": null, + "orderedProfileItems": [], + "profileItemsById": {}, + "blockIsActiveHold": false, + "blockTargetTempHold": null, + "lidIsActiveHold": false, + "lidTargetTempHold": null, + "lidOpenHold": null + }, + "b07b84ec-f362-440c-b2d8-3949d7169107": { + "id": "b07b84ec-f362-440c-b2d8-3949d7169107", + "stepType": "heaterShaker", + "stepName": "heater-shaker", + "stepDetails": "", + "moduleId": "5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType", + "setHeaterShakerTemperature": true, + "targetHeaterShakerTemperature": "55", + "targetSpeed": "1000", + "setShake": true, + "latchOpen": false, + "heaterShakerSetTimer": null, + "heaterShakerTimerMinutes": null, + "heaterShakerTimerSeconds": null + }, + "6231a6a8-e287-4e7b-8536-6aa836e29a59": { + "id": "6231a6a8-e287-4e7b-8536-6aa836e29a59", + "stepType": "pause", + "stepName": "pause", + "stepDetails": "", + "pauseAction": "untilTemperature", + "pauseHour": null, + "pauseMinute": null, + "pauseSecond": null, + "pauseMessage": "", + "moduleId": "5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType", + "pauseTemperature": "55" + }, + "bbc840b2-b509-42d9-81dc-428d5c91a978": { + "id": "bbc840b2-b509-42d9-81dc-428d5c91a978", + "stepType": "magnet", + "stepName": "magnet", + "stepDetails": "", + "moduleId": "8d4683d0-7a88-4b33-9363-bd3894a71f9a:magneticModuleType", + "magnetAction": "engage", + "engageHeight": "12" + }, + "0431038f-34af-412a-88a6-24a06ce8039f": { + "id": "0431038f-34af-412a-88a6-24a06ce8039f", + "stepType": "temperature", + "stepName": "temperature", + "stepDetails": "", + "moduleId": "b5df8f5c-9fc5-4d45-98c2-0ce6bd218fda:temperatureModuleType", + "setTemperature": "true", + "targetTemperature": "80" + }, + "230bc077-a866-45f1-a24b-66238c8ce670": { + "id": "230bc077-a866-45f1-a24b-66238c8ce670", + "stepType": "pause", + "stepName": "pause", + "stepDetails": "", + "pauseAction": "untilTemperature", + "pauseHour": null, + "pauseMinute": null, + "pauseSecond": null, + "pauseMessage": "", + "moduleId": "5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType", + "pauseTemperature": "80" + }, + "3ef16f4c-15ae-407f-9284-0730fd8160b5": { + "id": "3ef16f4c-15ae-407f-9284-0730fd8160b5", + "stepType": "heaterShaker", + "stepName": "heater-shaker", + "stepDetails": "", + "moduleId": "5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType", + "setHeaterShakerTemperature": null, + "targetHeaterShakerTemperature": null, + "targetSpeed": null, + "setShake": null, + "latchOpen": true, + "heaterShakerSetTimer": null, + "heaterShakerTimerMinutes": null, + "heaterShakerTimerSeconds": null + }, + "f83d54c3-76cf-4be3-ba10-fc551d9ec065": { + "id": "f83d54c3-76cf-4be3-ba10-fc551d9ec065", + "stepType": "thermocycler", + "stepName": "thermocycler", + "stepDetails": "", + "thermocyclerFormType": "thermocyclerState", + "moduleId": "a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType", + "blockIsActive": false, + "blockTargetTemp": null, + "lidIsActive": false, + "lidTargetTemp": null, + "lidOpen": true, + "profileVolume": null, + "profileTargetLidTemp": null, + "orderedProfileItems": [], + "profileItemsById": {}, + "blockIsActiveHold": false, + "blockTargetTempHold": null, + "lidIsActiveHold": false, + "lidTargetTempHold": null, + "lidOpenHold": null + } + }, + "orderedStepIds": [ + "8506adb8-05bc-49cd-a159-f1af3623012f", + "28f5eb49-8cac-4658-aa04-2021277f6026", + "5fe8dbb8-ccae-4ca8-8015-7d53fd182cb0", + "ba4d8515-524b-41cd-9953-72fe308e69f0", + "6dff24c4-13ad-4a0e-9eb8-66048f96ca0c", + "1e9d8a92-e791-452b-9275-638ae8206dda", + "ea9a9a34-6d2d-46f1-b10b-fb5d8d28d827", + "b07b84ec-f362-440c-b2d8-3949d7169107", + "6231a6a8-e287-4e7b-8536-6aa836e29a59", + "bbc840b2-b509-42d9-81dc-428d5c91a978", + "0431038f-34af-412a-88a6-24a06ce8039f", + "230bc077-a866-45f1-a24b-66238c8ce670", + "3ef16f4c-15ae-407f-9284-0730fd8160b5", + "f83d54c3-76cf-4be3-ba10-fc551d9ec065" + ] + } + }, + "robot": { + "model": "OT-2 Standard", + "deckId": "ot2_standard" + }, + "pipettes": { + "9467efbc-2ad4-40eb-bc05-91c78fd48be2": { + "name": "p300_multi_gen2" + }, + "1b766d4d-ba31-42cc-a49a-73e9d8c67aca": { + "name": "p300_single_gen2" + } + }, + "labware": { + "fixedTrash": { + "displayName": "Trash", + "definitionId": "opentrons/opentrons_1_trash_1100ml_fixed/1" + }, + "a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1": { + "displayName": "Opentrons 96 Tip Rack 300 µL", + "definitionId": "opentrons/opentrons_96_tiprack_300ul/1" + }, + "0d460f8a-2163-4eb7-8f48-5c382604971a:opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1": { + "displayName": "H/S", + "definitionId": "opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1" + }, + "01ab8b91-996c-41a2-a11e-57719913979e:opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1": { + "displayName": "Temp", + "definitionId": "opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1" + }, + "32e39cda-1d1d-4e0d-b933-b94cf464e29a:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1": { + "displayName": "Mag", + "definitionId": "opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1" + }, + "111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1": { + "displayName": "Themo", + "definitionId": "opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1" + }, + "bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1": { + "displayName": "L1", + "definitionId": "opentrons/agilent_1_reservoir_290ml/1" + } + }, + "liquids": { + "0": { + "displayName": "L1", + "description": "", + "displayColor": "#b925ff" + }, + "1": { + "displayName": "L2", + "description": "", + "displayColor": "#ffd600" + } + }, + "labwareDefinitions": { + "opentrons/opentrons_96_tiprack_300ul/1": { + "ordering": [ + [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1" + ], + [ + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2" + ], + [ + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3" + ], + [ + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4" + ], + [ + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5" + ], + [ + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6" + ], + [ + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7" + ], + [ + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8" + ], + [ + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9" + ], + [ + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10" + ], + [ + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11" + ], + [ + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ] + ], + "brand": { + "brand": "Opentrons", + "brandId": [], + "links": [ + "https://shop.opentrons.com/collections/opentrons-tips/products/opentrons-300ul-tips" + ] + }, + "metadata": { + "displayName": "Opentrons 96 Tip Rack 300 µL", + "displayCategory": "tipRack", + "displayVolumeUnits": "µL", + "tags": [] + }, + "dimensions": { + "xDimension": 127.76, + "yDimension": 85.48, + "zDimension": 64.49 + }, + "wells": { + "A1": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 14.38, + "y": 74.24, + "z": 5.39 + }, + "B1": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 14.38, + "y": 65.24, + "z": 5.39 + }, + "C1": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 14.38, + "y": 56.24, + "z": 5.39 + }, + "D1": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 14.38, + "y": 47.24, + "z": 5.39 + }, + "E1": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 14.38, + "y": 38.24, + "z": 5.39 + }, + "F1": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 14.38, + "y": 29.24, + "z": 5.39 + }, + "G1": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 14.38, + "y": 20.24, + "z": 5.39 + }, + "H1": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 14.38, + "y": 11.24, + "z": 5.39 + }, + "A2": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 23.38, + "y": 74.24, + "z": 5.39 + }, + "B2": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 23.38, + "y": 65.24, + "z": 5.39 + }, + "C2": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 23.38, + "y": 56.24, + "z": 5.39 + }, + "D2": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 23.38, + "y": 47.24, + "z": 5.39 + }, + "E2": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 23.38, + "y": 38.24, + "z": 5.39 + }, + "F2": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 23.38, + "y": 29.24, + "z": 5.39 + }, + "G2": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 23.38, + "y": 20.24, + "z": 5.39 + }, + "H2": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 23.38, + "y": 11.24, + "z": 5.39 + }, + "A3": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 32.38, + "y": 74.24, + "z": 5.39 + }, + "B3": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 32.38, + "y": 65.24, + "z": 5.39 + }, + "C3": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 32.38, + "y": 56.24, + "z": 5.39 + }, + "D3": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 32.38, + "y": 47.24, + "z": 5.39 + }, + "E3": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 32.38, + "y": 38.24, + "z": 5.39 + }, + "F3": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 32.38, + "y": 29.24, + "z": 5.39 + }, + "G3": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 32.38, + "y": 20.24, + "z": 5.39 + }, + "H3": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 32.38, + "y": 11.24, + "z": 5.39 + }, + "A4": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 41.38, + "y": 74.24, + "z": 5.39 + }, + "B4": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 41.38, + "y": 65.24, + "z": 5.39 + }, + "C4": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 41.38, + "y": 56.24, + "z": 5.39 + }, + "D4": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 41.38, + "y": 47.24, + "z": 5.39 + }, + "E4": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 41.38, + "y": 38.24, + "z": 5.39 + }, + "F4": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 41.38, + "y": 29.24, + "z": 5.39 + }, + "G4": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 41.38, + "y": 20.24, + "z": 5.39 + }, + "H4": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 41.38, + "y": 11.24, + "z": 5.39 + }, + "A5": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 50.38, + "y": 74.24, + "z": 5.39 + }, + "B5": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 50.38, + "y": 65.24, + "z": 5.39 + }, + "C5": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 50.38, + "y": 56.24, + "z": 5.39 + }, + "D5": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 50.38, + "y": 47.24, + "z": 5.39 + }, + "E5": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 50.38, + "y": 38.24, + "z": 5.39 + }, + "F5": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 50.38, + "y": 29.24, + "z": 5.39 + }, + "G5": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 50.38, + "y": 20.24, + "z": 5.39 + }, + "H5": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 50.38, + "y": 11.24, + "z": 5.39 + }, + "A6": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 59.38, + "y": 74.24, + "z": 5.39 + }, + "B6": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 59.38, + "y": 65.24, + "z": 5.39 + }, + "C6": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 59.38, + "y": 56.24, + "z": 5.39 + }, + "D6": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 59.38, + "y": 47.24, + "z": 5.39 + }, + "E6": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 59.38, + "y": 38.24, + "z": 5.39 + }, + "F6": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 59.38, + "y": 29.24, + "z": 5.39 + }, + "G6": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 59.38, + "y": 20.24, + "z": 5.39 + }, + "H6": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 59.38, + "y": 11.24, + "z": 5.39 + }, + "A7": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 68.38, + "y": 74.24, + "z": 5.39 + }, + "B7": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 68.38, + "y": 65.24, + "z": 5.39 + }, + "C7": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 68.38, + "y": 56.24, + "z": 5.39 + }, + "D7": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 68.38, + "y": 47.24, + "z": 5.39 + }, + "E7": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 68.38, + "y": 38.24, + "z": 5.39 + }, + "F7": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 68.38, + "y": 29.24, + "z": 5.39 + }, + "G7": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 68.38, + "y": 20.24, + "z": 5.39 + }, + "H7": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 68.38, + "y": 11.24, + "z": 5.39 + }, + "A8": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 77.38, + "y": 74.24, + "z": 5.39 + }, + "B8": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 77.38, + "y": 65.24, + "z": 5.39 + }, + "C8": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 77.38, + "y": 56.24, + "z": 5.39 + }, + "D8": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 77.38, + "y": 47.24, + "z": 5.39 + }, + "E8": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 77.38, + "y": 38.24, + "z": 5.39 + }, + "F8": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 77.38, + "y": 29.24, + "z": 5.39 + }, + "G8": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 77.38, + "y": 20.24, + "z": 5.39 + }, + "H8": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 77.38, + "y": 11.24, + "z": 5.39 + }, + "A9": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 86.38, + "y": 74.24, + "z": 5.39 + }, + "B9": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 86.38, + "y": 65.24, + "z": 5.39 + }, + "C9": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 86.38, + "y": 56.24, + "z": 5.39 + }, + "D9": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 86.38, + "y": 47.24, + "z": 5.39 + }, + "E9": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 86.38, + "y": 38.24, + "z": 5.39 + }, + "F9": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 86.38, + "y": 29.24, + "z": 5.39 + }, + "G9": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 86.38, + "y": 20.24, + "z": 5.39 + }, + "H9": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 86.38, + "y": 11.24, + "z": 5.39 + }, + "A10": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 95.38, + "y": 74.24, + "z": 5.39 + }, + "B10": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 95.38, + "y": 65.24, + "z": 5.39 + }, + "C10": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 95.38, + "y": 56.24, + "z": 5.39 + }, + "D10": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 95.38, + "y": 47.24, + "z": 5.39 + }, + "E10": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 95.38, + "y": 38.24, + "z": 5.39 + }, + "F10": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 95.38, + "y": 29.24, + "z": 5.39 + }, + "G10": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 95.38, + "y": 20.24, + "z": 5.39 + }, + "H10": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 95.38, + "y": 11.24, + "z": 5.39 + }, + "A11": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 104.38, + "y": 74.24, + "z": 5.39 + }, + "B11": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 104.38, + "y": 65.24, + "z": 5.39 + }, + "C11": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 104.38, + "y": 56.24, + "z": 5.39 + }, + "D11": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 104.38, + "y": 47.24, + "z": 5.39 + }, + "E11": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 104.38, + "y": 38.24, + "z": 5.39 + }, + "F11": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 104.38, + "y": 29.24, + "z": 5.39 + }, + "G11": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 104.38, + "y": 20.24, + "z": 5.39 + }, + "H11": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 104.38, + "y": 11.24, + "z": 5.39 + }, + "A12": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 113.38, + "y": 74.24, + "z": 5.39 + }, + "B12": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 113.38, + "y": 65.24, + "z": 5.39 + }, + "C12": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 113.38, + "y": 56.24, + "z": 5.39 + }, + "D12": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 113.38, + "y": 47.24, + "z": 5.39 + }, + "E12": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 113.38, + "y": 38.24, + "z": 5.39 + }, + "F12": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 113.38, + "y": 29.24, + "z": 5.39 + }, + "G12": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 113.38, + "y": 20.24, + "z": 5.39 + }, + "H12": { + "depth": 59.3, + "shape": "circular", + "diameter": 5.23, + "totalLiquidVolume": 300, + "x": 113.38, + "y": 11.24, + "z": 5.39 + } + }, + "groups": [ + { + "metadata": {}, + "wells": [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1", + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2", + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3", + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4", + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5", + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6", + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7", + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8", + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9", + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10", + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11", + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ] + } + ], + "parameters": { + "format": "96Standard", + "isTiprack": true, + "tipLength": 59.3, + "tipOverlap": 7.47, + "isMagneticModuleCompatible": false, + "loadName": "opentrons_96_tiprack_300ul" + }, + "namespace": "opentrons", + "version": 1, + "schemaVersion": 2, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + } + }, + "opentrons/opentrons_1_trash_1100ml_fixed/1": { + "ordering": [ + [ + "A1" + ] + ], + "metadata": { + "displayCategory": "trash", + "displayVolumeUnits": "mL", + "displayName": "Opentrons Fixed Trash", + "tags": [] + }, + "schemaVersion": 2, + "version": 1, + "namespace": "opentrons", + "dimensions": { + "xDimension": 172.86, + "yDimension": 165.86, + "zDimension": 82 + }, + "parameters": { + "format": "trash", + "isTiprack": false, + "loadName": "opentrons_1_trash_1100ml_fixed", + "isMagneticModuleCompatible": false, + "quirks": [ + "fixedTrash", + "centerMultichannelOnWells", + "touchTipDisabled" + ] + }, + "wells": { + "A1": { + "shape": "rectangular", + "yDimension": 165.67, + "xDimension": 107.11, + "totalLiquidVolume": 1100000, + "depth": 0, + "x": 82.84, + "y": 80, + "z": 82 + } + }, + "brand": { + "brand": "Opentrons" + }, + "groups": [ + { + "wells": [ + "A1" + ], + "metadata": {} + } + ], + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + } + }, + "opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1": { + "ordering": [ + [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1" + ], + [ + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2" + ], + [ + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3" + ], + [ + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4" + ], + [ + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5" + ], + [ + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6" + ], + [ + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7" + ], + [ + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8" + ], + [ + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9" + ], + [ + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10" + ], + [ + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11" + ], + [ + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ] + ], + "brand": { + "brand": "Opentrons", + "brandId": [], + "links": [] + }, + "metadata": { + "displayName": "Opentrons 96 Deep Well Adapter with NEST Deep Well Plate 2 mL", + "displayCategory": "aluminumBlock", + "displayVolumeUnits": "µL", + "tags": [] + }, + "dimensions": { + "xDimension": 127.6, + "yDimension": 85.3, + "zDimension": 42.25 + }, + "wells": { + "A1": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 14.3, + "y": 74.15, + "z": 4.25 + }, + "B1": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 14.3, + "y": 65.15, + "z": 4.25 + }, + "C1": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 14.3, + "y": 56.15, + "z": 4.25 + }, + "D1": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 14.3, + "y": 47.15, + "z": 4.25 + }, + "E1": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 14.3, + "y": 38.15, + "z": 4.25 + }, + "F1": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 14.3, + "y": 29.15, + "z": 4.25 + }, + "G1": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 14.3, + "y": 20.15, + "z": 4.25 + }, + "H1": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 14.3, + "y": 11.15, + "z": 4.25 + }, + "A2": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 23.3, + "y": 74.15, + "z": 4.25 + }, + "B2": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 23.3, + "y": 65.15, + "z": 4.25 + }, + "C2": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 23.3, + "y": 56.15, + "z": 4.25 + }, + "D2": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 23.3, + "y": 47.15, + "z": 4.25 + }, + "E2": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 23.3, + "y": 38.15, + "z": 4.25 + }, + "F2": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 23.3, + "y": 29.15, + "z": 4.25 + }, + "G2": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 23.3, + "y": 20.15, + "z": 4.25 + }, + "H2": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 23.3, + "y": 11.15, + "z": 4.25 + }, + "A3": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 32.3, + "y": 74.15, + "z": 4.25 + }, + "B3": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 32.3, + "y": 65.15, + "z": 4.25 + }, + "C3": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 32.3, + "y": 56.15, + "z": 4.25 + }, + "D3": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 32.3, + "y": 47.15, + "z": 4.25 + }, + "E3": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 32.3, + "y": 38.15, + "z": 4.25 + }, + "F3": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 32.3, + "y": 29.15, + "z": 4.25 + }, + "G3": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 32.3, + "y": 20.15, + "z": 4.25 + }, + "H3": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 32.3, + "y": 11.15, + "z": 4.25 + }, + "A4": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 41.3, + "y": 74.15, + "z": 4.25 + }, + "B4": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 41.3, + "y": 65.15, + "z": 4.25 + }, + "C4": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 41.3, + "y": 56.15, + "z": 4.25 + }, + "D4": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 41.3, + "y": 47.15, + "z": 4.25 + }, + "E4": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 41.3, + "y": 38.15, + "z": 4.25 + }, + "F4": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 41.3, + "y": 29.15, + "z": 4.25 + }, + "G4": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 41.3, + "y": 20.15, + "z": 4.25 + }, + "H4": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 41.3, + "y": 11.15, + "z": 4.25 + }, + "A5": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 50.3, + "y": 74.15, + "z": 4.25 + }, + "B5": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 50.3, + "y": 65.15, + "z": 4.25 + }, + "C5": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 50.3, + "y": 56.15, + "z": 4.25 + }, + "D5": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 50.3, + "y": 47.15, + "z": 4.25 + }, + "E5": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 50.3, + "y": 38.15, + "z": 4.25 + }, + "F5": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 50.3, + "y": 29.15, + "z": 4.25 + }, + "G5": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 50.3, + "y": 20.15, + "z": 4.25 + }, + "H5": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 50.3, + "y": 11.15, + "z": 4.25 + }, + "A6": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 59.3, + "y": 74.15, + "z": 4.25 + }, + "B6": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 59.3, + "y": 65.15, + "z": 4.25 + }, + "C6": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 59.3, + "y": 56.15, + "z": 4.25 + }, + "D6": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 59.3, + "y": 47.15, + "z": 4.25 + }, + "E6": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 59.3, + "y": 38.15, + "z": 4.25 + }, + "F6": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 59.3, + "y": 29.15, + "z": 4.25 + }, + "G6": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 59.3, + "y": 20.15, + "z": 4.25 + }, + "H6": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 59.3, + "y": 11.15, + "z": 4.25 + }, + "A7": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 68.3, + "y": 74.15, + "z": 4.25 + }, + "B7": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 68.3, + "y": 65.15, + "z": 4.25 + }, + "C7": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 68.3, + "y": 56.15, + "z": 4.25 + }, + "D7": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 68.3, + "y": 47.15, + "z": 4.25 + }, + "E7": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 68.3, + "y": 38.15, + "z": 4.25 + }, + "F7": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 68.3, + "y": 29.15, + "z": 4.25 + }, + "G7": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 68.3, + "y": 20.15, + "z": 4.25 + }, + "H7": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 68.3, + "y": 11.15, + "z": 4.25 + }, + "A8": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 77.3, + "y": 74.15, + "z": 4.25 + }, + "B8": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 77.3, + "y": 65.15, + "z": 4.25 + }, + "C8": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 77.3, + "y": 56.15, + "z": 4.25 + }, + "D8": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 77.3, + "y": 47.15, + "z": 4.25 + }, + "E8": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 77.3, + "y": 38.15, + "z": 4.25 + }, + "F8": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 77.3, + "y": 29.15, + "z": 4.25 + }, + "G8": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 77.3, + "y": 20.15, + "z": 4.25 + }, + "H8": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 77.3, + "y": 11.15, + "z": 4.25 + }, + "A9": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 86.3, + "y": 74.15, + "z": 4.25 + }, + "B9": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 86.3, + "y": 65.15, + "z": 4.25 + }, + "C9": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 86.3, + "y": 56.15, + "z": 4.25 + }, + "D9": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 86.3, + "y": 47.15, + "z": 4.25 + }, + "E9": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 86.3, + "y": 38.15, + "z": 4.25 + }, + "F9": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 86.3, + "y": 29.15, + "z": 4.25 + }, + "G9": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 86.3, + "y": 20.15, + "z": 4.25 + }, + "H9": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 86.3, + "y": 11.15, + "z": 4.25 + }, + "A10": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 95.3, + "y": 74.15, + "z": 4.25 + }, + "B10": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 95.3, + "y": 65.15, + "z": 4.25 + }, + "C10": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 95.3, + "y": 56.15, + "z": 4.25 + }, + "D10": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 95.3, + "y": 47.15, + "z": 4.25 + }, + "E10": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 95.3, + "y": 38.15, + "z": 4.25 + }, + "F10": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 95.3, + "y": 29.15, + "z": 4.25 + }, + "G10": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 95.3, + "y": 20.15, + "z": 4.25 + }, + "H10": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 95.3, + "y": 11.15, + "z": 4.25 + }, + "A11": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 104.3, + "y": 74.15, + "z": 4.25 + }, + "B11": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 104.3, + "y": 65.15, + "z": 4.25 + }, + "C11": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 104.3, + "y": 56.15, + "z": 4.25 + }, + "D11": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 104.3, + "y": 47.15, + "z": 4.25 + }, + "E11": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 104.3, + "y": 38.15, + "z": 4.25 + }, + "F11": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 104.3, + "y": 29.15, + "z": 4.25 + }, + "G11": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 104.3, + "y": 20.15, + "z": 4.25 + }, + "H11": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 104.3, + "y": 11.15, + "z": 4.25 + }, + "A12": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 113.3, + "y": 74.15, + "z": 4.25 + }, + "B12": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 113.3, + "y": 65.15, + "z": 4.25 + }, + "C12": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 113.3, + "y": 56.15, + "z": 4.25 + }, + "D12": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 113.3, + "y": 47.15, + "z": 4.25 + }, + "E12": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 113.3, + "y": 38.15, + "z": 4.25 + }, + "F12": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 113.3, + "y": 29.15, + "z": 4.25 + }, + "G12": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 113.3, + "y": 20.15, + "z": 4.25 + }, + "H12": { + "depth": 38, + "totalLiquidVolume": 2000, + "shape": "rectangular", + "xDimension": 8.2, + "yDimension": 8.2, + "x": 113.3, + "y": 11.15, + "z": 4.25 + } + }, + "groups": [ + { + "metadata": { + "displayName": "NEST 96 Deepwell Plate 2mL", + "displayCategory": "wellPlate", + "wellBottomShape": "v" + }, + "brand": { + "brand": "NEST", + "brandId": [ + "503501", + "503001" + ], + "links": [ + "https://www.nest-biotech.com/deep-well-plates/59253726.html" + ] + }, + "wells": [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1", + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2", + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3", + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4", + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5", + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6", + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7", + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8", + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9", + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10", + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11", + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ] + } + ], + "parameters": { + "format": "96Standard", + "quirks": [], + "isTiprack": false, + "isMagneticModuleCompatible": false, + "loadName": "opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep" + }, + "namespace": "opentrons", + "version": 1, + "schemaVersion": 2, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + } + }, + "opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1": { + "ordering": [ + [ + "A1", + "B1", + "C1", + "D1" + ], + [ + "A2", + "B2", + "C2", + "D2" + ], + [ + "A3", + "B3", + "C3", + "D3" + ], + [ + "A4", + "B4", + "C4", + "D4" + ], + [ + "A5", + "B5", + "C5", + "D5" + ], + [ + "A6", + "B6", + "C6", + "D6" + ] + ], + "schemaVersion": 2, + "version": 1, + "namespace": "opentrons", + "metadata": { + "displayName": "Opentrons 24 Well Aluminum Block with Generic 2 mL Screwcap", + "displayVolumeUnits": "mL", + "displayCategory": "aluminumBlock", + "tags": [] + }, + "dimensions": { + "xDimension": 127.75, + "yDimension": 85.5, + "zDimension": 42 + }, + "parameters": { + "format": "irregular", + "isTiprack": false, + "isMagneticModuleCompatible": false, + "loadName": "opentrons_24_aluminumblock_generic_2ml_screwcap" + }, + "wells": { + "D1": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 20.75, + "y": 16.88, + "z": 6.7 + }, + "C1": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 20.75, + "y": 34.13, + "z": 6.7 + }, + "B1": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 20.75, + "y": 51.38, + "z": 6.7 + }, + "A1": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 20.75, + "y": 68.63, + "z": 6.7 + }, + "D2": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 38, + "y": 16.88, + "z": 6.7 + }, + "C2": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 38, + "y": 34.13, + "z": 6.7 + }, + "B2": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 38, + "y": 51.38, + "z": 6.7 + }, + "A2": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 38, + "y": 68.63, + "z": 6.7 + }, + "D3": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 55.25, + "y": 16.88, + "z": 6.7 + }, + "C3": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 55.25, + "y": 34.13, + "z": 6.7 + }, + "B3": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 55.25, + "y": 51.38, + "z": 6.7 + }, + "A3": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 55.25, + "y": 68.63, + "z": 6.7 + }, + "D4": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 72.5, + "y": 16.88, + "z": 6.7 + }, + "C4": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 72.5, + "y": 34.13, + "z": 6.7 + }, + "B4": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 72.5, + "y": 51.38, + "z": 6.7 + }, + "A4": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 72.5, + "y": 68.63, + "z": 6.7 + }, + "D5": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 89.75, + "y": 16.88, + "z": 6.7 + }, + "C5": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 89.75, + "y": 34.13, + "z": 6.7 + }, + "B5": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 89.75, + "y": 51.38, + "z": 6.7 + }, + "A5": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 89.75, + "y": 68.63, + "z": 6.7 + }, + "D6": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 107, + "y": 16.88, + "z": 6.7 + }, + "C6": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 107, + "y": 34.13, + "z": 6.7 + }, + "B6": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 107, + "y": 51.38, + "z": 6.7 + }, + "A6": { + "shape": "circular", + "depth": 42, + "diameter": 8.5, + "totalLiquidVolume": 2000, + "x": 107, + "y": 68.63, + "z": 6.7 + } + }, + "brand": { + "brand": "Opentrons", + "brandId": [], + "links": [ + "https://shop.opentrons.com/collections/hardware-modules/products/aluminum-block-set" + ] + }, + "groups": [ + { + "wells": [ + "A1", + "B1", + "C1", + "D1", + "A2", + "B2", + "C2", + "D2", + "A3", + "B3", + "C3", + "D3", + "A4", + "B4", + "C4", + "D4", + "A5", + "B5", + "C5", + "D5", + "A6", + "B6", + "C6", + "D6" + ], + "metadata": { + "displayName": "Generic 2 mL Screwcap", + "displayCategory": "tubeRack", + "wellBottomShape": "v" + }, + "brand": { + "brand": "generic", + "brandId": [], + "links": [] + } + } + ], + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + } + }, + "opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1": { + "ordering": [ + [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1" + ], + [ + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2" + ], + [ + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3" + ], + [ + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4" + ], + [ + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5" + ], + [ + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6" + ], + [ + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7" + ], + [ + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8" + ], + [ + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9" + ], + [ + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10" + ], + [ + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11" + ], + [ + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ] + ], + "brand": { + "brand": "NEST", + "brandId": [ + "402501" + ], + "links": [ + "https://www.nest-biotech.com/pcr-plates/58773587.html" + ] + }, + "metadata": { + "displayName": "NEST 96 Well Plate 100 µL PCR Full Skirt", + "displayCategory": "wellPlate", + "displayVolumeUnits": "µL", + "tags": [] + }, + "dimensions": { + "xDimension": 127.76, + "yDimension": 85.48, + "zDimension": 15.7 + }, + "wells": { + "A1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 14.38, + "y": 74.24, + "z": 0.92 + }, + "B1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 14.38, + "y": 65.24, + "z": 0.92 + }, + "C1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 14.38, + "y": 56.24, + "z": 0.92 + }, + "D1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 14.38, + "y": 47.24, + "z": 0.92 + }, + "E1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 14.38, + "y": 38.24, + "z": 0.92 + }, + "F1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 14.38, + "y": 29.24, + "z": 0.92 + }, + "G1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 14.38, + "y": 20.24, + "z": 0.92 + }, + "H1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 14.38, + "y": 11.24, + "z": 0.92 + }, + "A2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 23.38, + "y": 74.24, + "z": 0.92 + }, + "B2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 23.38, + "y": 65.24, + "z": 0.92 + }, + "C2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 23.38, + "y": 56.24, + "z": 0.92 + }, + "D2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 23.38, + "y": 47.24, + "z": 0.92 + }, + "E2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 23.38, + "y": 38.24, + "z": 0.92 + }, + "F2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 23.38, + "y": 29.24, + "z": 0.92 + }, + "G2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 23.38, + "y": 20.24, + "z": 0.92 + }, + "H2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 23.38, + "y": 11.24, + "z": 0.92 + }, + "A3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 32.38, + "y": 74.24, + "z": 0.92 + }, + "B3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 32.38, + "y": 65.24, + "z": 0.92 + }, + "C3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 32.38, + "y": 56.24, + "z": 0.92 + }, + "D3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 32.38, + "y": 47.24, + "z": 0.92 + }, + "E3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 32.38, + "y": 38.24, + "z": 0.92 + }, + "F3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 32.38, + "y": 29.24, + "z": 0.92 + }, + "G3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 32.38, + "y": 20.24, + "z": 0.92 + }, + "H3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 32.38, + "y": 11.24, + "z": 0.92 + }, + "A4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 41.38, + "y": 74.24, + "z": 0.92 + }, + "B4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 41.38, + "y": 65.24, + "z": 0.92 + }, + "C4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 41.38, + "y": 56.24, + "z": 0.92 + }, + "D4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 41.38, + "y": 47.24, + "z": 0.92 + }, + "E4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 41.38, + "y": 38.24, + "z": 0.92 + }, + "F4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 41.38, + "y": 29.24, + "z": 0.92 + }, + "G4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 41.38, + "y": 20.24, + "z": 0.92 + }, + "H4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 41.38, + "y": 11.24, + "z": 0.92 + }, + "A5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 50.38, + "y": 74.24, + "z": 0.92 + }, + "B5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 50.38, + "y": 65.24, + "z": 0.92 + }, + "C5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 50.38, + "y": 56.24, + "z": 0.92 + }, + "D5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 50.38, + "y": 47.24, + "z": 0.92 + }, + "E5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 50.38, + "y": 38.24, + "z": 0.92 + }, + "F5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 50.38, + "y": 29.24, + "z": 0.92 + }, + "G5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 50.38, + "y": 20.24, + "z": 0.92 + }, + "H5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 50.38, + "y": 11.24, + "z": 0.92 + }, + "A6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 59.38, + "y": 74.24, + "z": 0.92 + }, + "B6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 59.38, + "y": 65.24, + "z": 0.92 + }, + "C6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 59.38, + "y": 56.24, + "z": 0.92 + }, + "D6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 59.38, + "y": 47.24, + "z": 0.92 + }, + "E6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 59.38, + "y": 38.24, + "z": 0.92 + }, + "F6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 59.38, + "y": 29.24, + "z": 0.92 + }, + "G6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 59.38, + "y": 20.24, + "z": 0.92 + }, + "H6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 59.38, + "y": 11.24, + "z": 0.92 + }, + "A7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 68.38, + "y": 74.24, + "z": 0.92 + }, + "B7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 68.38, + "y": 65.24, + "z": 0.92 + }, + "C7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 68.38, + "y": 56.24, + "z": 0.92 + }, + "D7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 68.38, + "y": 47.24, + "z": 0.92 + }, + "E7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 68.38, + "y": 38.24, + "z": 0.92 + }, + "F7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 68.38, + "y": 29.24, + "z": 0.92 + }, + "G7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 68.38, + "y": 20.24, + "z": 0.92 + }, + "H7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 68.38, + "y": 11.24, + "z": 0.92 + }, + "A8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 77.38, + "y": 74.24, + "z": 0.92 + }, + "B8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 77.38, + "y": 65.24, + "z": 0.92 + }, + "C8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 77.38, + "y": 56.24, + "z": 0.92 + }, + "D8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 77.38, + "y": 47.24, + "z": 0.92 + }, + "E8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 77.38, + "y": 38.24, + "z": 0.92 + }, + "F8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 77.38, + "y": 29.24, + "z": 0.92 + }, + "G8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 77.38, + "y": 20.24, + "z": 0.92 + }, + "H8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 77.38, + "y": 11.24, + "z": 0.92 + }, + "A9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 86.38, + "y": 74.24, + "z": 0.92 + }, + "B9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 86.38, + "y": 65.24, + "z": 0.92 + }, + "C9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 86.38, + "y": 56.24, + "z": 0.92 + }, + "D9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 86.38, + "y": 47.24, + "z": 0.92 + }, + "E9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 86.38, + "y": 38.24, + "z": 0.92 + }, + "F9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 86.38, + "y": 29.24, + "z": 0.92 + }, + "G9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 86.38, + "y": 20.24, + "z": 0.92 + }, + "H9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 86.38, + "y": 11.24, + "z": 0.92 + }, + "A10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 95.38, + "y": 74.24, + "z": 0.92 + }, + "B10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 95.38, + "y": 65.24, + "z": 0.92 + }, + "C10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 95.38, + "y": 56.24, + "z": 0.92 + }, + "D10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 95.38, + "y": 47.24, + "z": 0.92 + }, + "E10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 95.38, + "y": 38.24, + "z": 0.92 + }, + "F10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 95.38, + "y": 29.24, + "z": 0.92 + }, + "G10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 95.38, + "y": 20.24, + "z": 0.92 + }, + "H10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 95.38, + "y": 11.24, + "z": 0.92 + }, + "A11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 104.38, + "y": 74.24, + "z": 0.92 + }, + "B11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 104.38, + "y": 65.24, + "z": 0.92 + }, + "C11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 104.38, + "y": 56.24, + "z": 0.92 + }, + "D11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 104.38, + "y": 47.24, + "z": 0.92 + }, + "E11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 104.38, + "y": 38.24, + "z": 0.92 + }, + "F11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 104.38, + "y": 29.24, + "z": 0.92 + }, + "G11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 104.38, + "y": 20.24, + "z": 0.92 + }, + "H11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 104.38, + "y": 11.24, + "z": 0.92 + }, + "A12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 113.38, + "y": 74.24, + "z": 0.92 + }, + "B12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 113.38, + "y": 65.24, + "z": 0.92 + }, + "C12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 113.38, + "y": 56.24, + "z": 0.92 + }, + "D12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 113.38, + "y": 47.24, + "z": 0.92 + }, + "E12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 113.38, + "y": 38.24, + "z": 0.92 + }, + "F12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 113.38, + "y": 29.24, + "z": 0.92 + }, + "G12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 113.38, + "y": 20.24, + "z": 0.92 + }, + "H12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 113.38, + "y": 11.24, + "z": 0.92 + } + }, + "groups": [ + { + "metadata": { + "wellBottomShape": "v" + }, + "wells": [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1", + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2", + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3", + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4", + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5", + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6", + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7", + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8", + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9", + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10", + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11", + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ] + } + ], + "parameters": { + "format": "96Standard", + "isTiprack": false, + "isMagneticModuleCompatible": true, + "magneticModuleEngageHeight": 20, + "loadName": "nest_96_wellplate_100ul_pcr_full_skirt" + }, + "namespace": "opentrons", + "version": 1, + "schemaVersion": 2, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + } + }, + "opentrons/agilent_1_reservoir_290ml/1": { + "ordering": [ + [ + "A1" + ] + ], + "brand": { + "brand": "Agilent", + "brandId": [ + "201252-100" + ], + "links": [ + "https://www.agilent.com/store/en_US/Prod-201252-100/201252-100" + ] + }, + "metadata": { + "displayName": "Agilent 1 Well Reservoir 290 mL", + "displayCategory": "reservoir", + "displayVolumeUnits": "mL", + "tags": [] + }, + "dimensions": { + "xDimension": 127.76, + "yDimension": 85.57, + "zDimension": 44.04 + }, + "wells": { + "A1": { + "depth": 39.22, + "shape": "rectangular", + "xDimension": 108, + "yDimension": 72, + "totalLiquidVolume": 290000, + "x": 63.88, + "y": 42.785, + "z": 4.82 + } + }, + "groups": [ + { + "wells": [ + "A1" + ], + "metadata": { + "wellBottomShape": "v" + } + } + ], + "parameters": { + "format": "trough", + "isTiprack": false, + "isMagneticModuleCompatible": false, + "loadName": "agilent_1_reservoir_290ml", + "quirks": [ + "centerMultichannelOnWells", + "touchTipDisabled" + ] + }, + "namespace": "opentrons", + "version": 1, + "schemaVersion": 2, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + } + } + }, + "$otSharedSchema": "#/protocol/schemas/6", + "schemaVersion": 6, + "modules": { + "5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType": { + "model": "heaterShakerModuleV1" + }, + "8d4683d0-7a88-4b33-9363-bd3894a71f9a:magneticModuleType": { + "model": "magneticModuleV1" + }, + "b5df8f5c-9fc5-4d45-98c2-0ce6bd218fda:temperatureModuleType": { + "model": "temperatureModuleV1" + }, + "a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType": { + "model": "thermocyclerModuleV1" + } + }, + "commands": [ + { + "key": "9fb4e8f4-186e-4063-aafe-847b7f5f5cad", + "commandType": "loadPipette", + "params": { + "pipetteId": "9467efbc-2ad4-40eb-bc05-91c78fd48be2", + "mount": "left" + } + }, + { + "key": "789dde75-0ec2-490c-ab51-16f0d162e638", + "commandType": "loadPipette", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "mount": "right" + } + }, + { + "key": "42b2a4d7-403c-43bd-bc44-e61930576339", + "commandType": "loadModule", + "params": { + "moduleId": "5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType", + "location": { + "slotName": "1" + } + } + }, + { + "key": "5518b369-b938-4ac4-b2ba-adde29927e2a", + "commandType": "loadModule", + "params": { + "moduleId": "8d4683d0-7a88-4b33-9363-bd3894a71f9a:magneticModuleType", + "location": { + "slotName": "9" + } + } + }, + { + "key": "40f6b56d-05f1-46ab-a262-24601afb0f51", + "commandType": "loadModule", + "params": { + "moduleId": "b5df8f5c-9fc5-4d45-98c2-0ce6bd218fda:temperatureModuleType", + "location": { + "slotName": "3" + } + } + }, + { + "key": "3ae25b1b-2242-423a-8fb4-3f682dececd0", + "commandType": "loadModule", + "params": { + "moduleId": "a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType", + "location": { + "slotName": "7" + } + } + }, + { + "key": "d458d31a-bf76-40ec-97e5-113e27bea5fd", + "commandType": "loadLabware", + "params": { + "labwareId": "a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1", + "location": { + "slotName": "5" + } + } + }, + { + "key": "4cc07fbd-92e7-4454-ab09-2d150afbfee6", + "commandType": "loadLabware", + "params": { + "labwareId": "0d460f8a-2163-4eb7-8f48-5c382604971a:opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1", + "location": { + "moduleId": "5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType" + } + } + }, + { + "key": "7084ef04-3926-4bdb-bfba-0cef939464bd", + "commandType": "loadLabware", + "params": { + "labwareId": "01ab8b91-996c-41a2-a11e-57719913979e:opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1", + "location": { + "moduleId": "b5df8f5c-9fc5-4d45-98c2-0ce6bd218fda:temperatureModuleType" + } + } + }, + { + "key": "416661fd-3da9-4f83-9401-18454a9a18e2", + "commandType": "loadLabware", + "params": { + "labwareId": "32e39cda-1d1d-4e0d-b933-b94cf464e29a:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1", + "location": { + "moduleId": "8d4683d0-7a88-4b33-9363-bd3894a71f9a:magneticModuleType" + } + } + }, + { + "key": "f9b8458a-cf8b-47f9-8726-70364a361821", + "commandType": "loadLabware", + "params": { + "labwareId": "111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1", + "location": { + "moduleId": "a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType" + } + } + }, + { + "key": "e6b14558-83dd-46a0-88a8-7e7dc38a8869", + "commandType": "loadLabware", + "params": { + "labwareId": "bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1", + "location": { + "slotName": "6" + } + } + }, + { + "commandType": "loadLiquid", + "key": "2da37722-8a55-4955-aace-409ba03378df", + "params": { + "liquidId": "1", + "labwareId": "01ab8b91-996c-41a2-a11e-57719913979e:opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1", + "volumeByWell": { + "A1": 300, + "B1": 300, + "C1": 300, + "D1": 300, + "A2": 300, + "B2": 300, + "C2": 300, + "D2": 300 + } + } + }, + { + "commandType": "loadLiquid", + "key": "8c92f196-8a7f-47b2-83d3-1526db9a39db", + "params": { + "liquidId": "1", + "labwareId": "0d460f8a-2163-4eb7-8f48-5c382604971a:opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1", + "volumeByWell": { + "A1": 20, + "B1": 20, + "C1": 20, + "D1": 20, + "E1": 20, + "F1": 20, + "G1": 20, + "H1": 20, + "A2": 20, + "B2": 20, + "C2": 20, + "D2": 20, + "E2": 20, + "F2": 20, + "G2": 20, + "H2": 20, + "A3": 20, + "B3": 20, + "C3": 20, + "D3": 20, + "E3": 20, + "F3": 20, + "G3": 20, + "H3": 20 + } + } + }, + { + "commandType": "loadLiquid", + "key": "9d29b8c9-0f68-4d9a-89ac-c3509674d6ab", + "params": { + "liquidId": "1", + "labwareId": "111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1", + "volumeByWell": { + "A1": 100, + "B1": 100, + "C1": 100, + "D1": 100, + "E1": 100, + "F1": 100, + "G1": 100, + "H1": 100, + "A2": 100, + "B2": 100, + "C2": 100, + "D2": 100, + "E2": 100, + "F2": 100, + "G2": 100, + "H2": 100, + "A3": 100, + "B3": 100, + "C3": 100, + "D3": 100, + "E3": 100, + "F3": 100, + "G3": 100, + "H3": 100, + "A4": 100, + "B4": 100, + "C4": 100, + "D4": 100, + "E4": 100, + "F4": 100, + "G4": 100, + "H4": 100, + "A5": 100, + "B5": 100, + "C5": 100, + "D5": 100, + "E5": 100, + "F5": 100, + "G5": 100, + "H5": 100, + "A6": 100, + "B6": 100, + "C6": 100, + "D6": 100, + "E6": 100, + "F6": 100, + "G6": 100, + "H6": 100 + } + } + }, + { + "commandType": "loadLiquid", + "key": "d9c86281-67c0-432a-8fb2-3a200f280e5e", + "params": { + "liquidId": "1", + "labwareId": "32e39cda-1d1d-4e0d-b933-b94cf464e29a:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1", + "volumeByWell": { + "A1": 100, + "B1": 100, + "C1": 100, + "D1": 100, + "E1": 100, + "F1": 100, + "G1": 100, + "H1": 100, + "A2": 100, + "B2": 100, + "C2": 100, + "D2": 100, + "E2": 100, + "F2": 100, + "G2": 100, + "H2": 100, + "A3": 100, + "B3": 100, + "C3": 100, + "D3": 100, + "E3": 100, + "F3": 100, + "G3": 100, + "H3": 100, + "A4": 100, + "B4": 100, + "C4": 100, + "D4": 100, + "E4": 100, + "F4": 100, + "G4": 100, + "H4": 100, + "A5": 100, + "B5": 100, + "C5": 100, + "D5": 100, + "E5": 100, + "F5": 100, + "G5": 100, + "H5": 100, + "A6": 100, + "B6": 100, + "C6": 100, + "D6": 100, + "E6": 100, + "F6": 100, + "G6": 100, + "H6": 100 + } + } + }, + { + "commandType": "loadLiquid", + "key": "b000cefe-8e3e-45d3-85e3-efe29e8ed4ec", + "params": { + "liquidId": "0", + "labwareId": "bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1", + "volumeByWell": { + "A1": 29000 + } + } + }, + { + "commandType": "heaterShaker/closeLabwareLatch", + "key": "57a860ec-3a3f-4b94-804d-dc4ebc3913cb", + "params": { + "moduleId": "5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType" + } + }, + { + "commandType": "heaterShaker/deactivateHeater", + "key": "30cddb2c-0a38-4d81-a8aa-1f355895dbe9", + "params": { + "moduleId": "5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType" + } + }, + { + "commandType": "heaterShaker/deactivateShaker", + "key": "ef4ce9a1-61e7-4aed-a4ae-24c066236368", + "params": { + "moduleId": "5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType" + } + }, + { + "commandType": "thermocycler/openLid", + "key": "8f2eb96e-eb4c-476e-8bdf-0d27684beb09", + "params": { + "moduleId": "a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType" + } + }, + { + "commandType": "pickUpTip", + "key": "9583b372-b0a7-407a-b4a5-e847dd691beb", + "params": { + "pipetteId": "9467efbc-2ad4-40eb-bc05-91c78fd48be2", + "labwareId": "a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1", + "wellName": "A1" + } + }, + { + "commandType": "aspirate", + "key": "55fc7a88-02c8-45ef-87f6-a44c8f3d11db", + "params": { + "pipetteId": "9467efbc-2ad4-40eb-bc05-91c78fd48be2", + "volume": 20, + "labwareId": "bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1", + "wellName": "A1", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 1 + } + }, + "flowRate": 94 + } + }, + { + "commandType": "dispense", + "key": "e004e404-9481-4c56-ad5a-96a37a6b81c9", + "params": { + "pipetteId": "9467efbc-2ad4-40eb-bc05-91c78fd48be2", + "volume": 20, + "labwareId": "0d460f8a-2163-4eb7-8f48-5c382604971a:opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1", + "wellName": "A4", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 0.5 + } + }, + "flowRate": 94 + } + }, + { + "commandType": "dropTip", + "key": "fa620ea5-73c3-419f-8c37-197bbfb45d45", + "params": { + "pipetteId": "9467efbc-2ad4-40eb-bc05-91c78fd48be2", + "labwareId": "fixedTrash", + "wellName": "A1" + } + }, + { + "commandType": "pickUpTip", + "key": "37f23342-5406-43c4-9d2b-4f8e66a9b372", + "params": { + "pipetteId": "9467efbc-2ad4-40eb-bc05-91c78fd48be2", + "labwareId": "a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1", + "wellName": "A2" + } + }, + { + "commandType": "aspirate", + "key": "3d949fd7-45f8-4b57-a02d-3e5462d92483", + "params": { + "pipetteId": "9467efbc-2ad4-40eb-bc05-91c78fd48be2", + "volume": 20, + "labwareId": "bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1", + "wellName": "A1", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 1 + } + }, + "flowRate": 94 + } + }, + { + "commandType": "dispense", + "key": "39106345-35da-49ce-9683-8f0d551cb98f", + "params": { + "pipetteId": "9467efbc-2ad4-40eb-bc05-91c78fd48be2", + "volume": 20, + "labwareId": "32e39cda-1d1d-4e0d-b933-b94cf464e29a:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1", + "wellName": "A7", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 0.5 + } + }, + "flowRate": 94 + } + }, + { + "commandType": "dropTip", + "key": "9b7b49e5-8923-4e11-bf18-3da29a7ddf77", + "params": { + "pipetteId": "9467efbc-2ad4-40eb-bc05-91c78fd48be2", + "labwareId": "fixedTrash", + "wellName": "A1" + } + }, + { + "commandType": "pickUpTip", + "key": "0c165af0-08c0-4c5d-937a-4709e02ca85f", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "labwareId": "a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1", + "wellName": "A3" + } + }, + { + "commandType": "aspirate", + "key": "aaeae20e-8acb-4af0-a03e-676ed9451166", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "volume": 25, + "labwareId": "bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1", + "wellName": "A1", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 1 + } + }, + "flowRate": 46.43 + } + }, + { + "commandType": "dispense", + "key": "a36a645b-9d7f-41c3-b04b-1785fb3001b9", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "volume": 25, + "labwareId": "01ab8b91-996c-41a2-a11e-57719913979e:opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1", + "wellName": "A3", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 0.5 + } + }, + "flowRate": 46.43 + } + }, + { + "commandType": "dropTip", + "key": "f1816015-6ada-48e7-b879-4a2ea647339e", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "labwareId": "fixedTrash", + "wellName": "A1" + } + }, + { + "commandType": "pickUpTip", + "key": "f731b034-77de-4a42-bf48-3bb52b28bd45", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "labwareId": "a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1", + "wellName": "B3" + } + }, + { + "commandType": "aspirate", + "key": "0abfe1b2-89a4-4e6c-8078-a811dace2224", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "volume": 25, + "labwareId": "bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1", + "wellName": "A1", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 1 + } + }, + "flowRate": 46.43 + } + }, + { + "commandType": "dispense", + "key": "961ab4c8-da15-4350-ae65-470efc9b2238", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "volume": 25, + "labwareId": "01ab8b91-996c-41a2-a11e-57719913979e:opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1", + "wellName": "B3", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 0.5 + } + }, + "flowRate": 46.43 + } + }, + { + "commandType": "dropTip", + "key": "cbd55095-b432-41eb-ab53-109553e27b6a", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "labwareId": "fixedTrash", + "wellName": "A1" + } + }, + { + "commandType": "pickUpTip", + "key": "2144b06e-e692-466d-a802-6f60db8d6df3", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "labwareId": "a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1", + "wellName": "C3" + } + }, + { + "commandType": "aspirate", + "key": "fc30f4e1-2e26-4cfc-95b7-abd1cdab5add", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "volume": 25, + "labwareId": "bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1", + "wellName": "A1", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 1 + } + }, + "flowRate": 46.43 + } + }, + { + "commandType": "dispense", + "key": "81707a0d-d590-4c95-9ea2-288e61244e23", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "volume": 25, + "labwareId": "01ab8b91-996c-41a2-a11e-57719913979e:opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1", + "wellName": "C3", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 0.5 + } + }, + "flowRate": 46.43 + } + }, + { + "commandType": "dropTip", + "key": "e86624e9-17b4-4e4c-a818-99aa3b7203b4", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "labwareId": "fixedTrash", + "wellName": "A1" + } + }, + { + "commandType": "pickUpTip", + "key": "05753124-aa01-48c8-805f-ff3c76b50ad2", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "labwareId": "a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1", + "wellName": "D3" + } + }, + { + "commandType": "aspirate", + "key": "e56550a7-3894-4060-b8e9-6133aba946de", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "volume": 25, + "labwareId": "bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1", + "wellName": "A1", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 1 + } + }, + "flowRate": 46.43 + } + }, + { + "commandType": "dispense", + "key": "b241d60c-4cec-4a73-b9c4-d787747125f5", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "volume": 25, + "labwareId": "01ab8b91-996c-41a2-a11e-57719913979e:opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1", + "wellName": "D3", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 0.5 + } + }, + "flowRate": 46.43 + } + }, + { + "commandType": "dropTip", + "key": "3df64ca9-dc43-4eb6-94b6-09ad696e3e2e", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "labwareId": "fixedTrash", + "wellName": "A1" + } + }, + { + "commandType": "pickUpTip", + "key": "7d471a9a-2a78-4cab-85d9-ef537f01135e", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "labwareId": "a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1", + "wellName": "E3" + } + }, + { + "commandType": "aspirate", + "key": "1ebef344-1ba8-40dc-b233-c71095d643a1", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "volume": 22, + "labwareId": "bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1", + "wellName": "A1", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 1 + } + }, + "flowRate": 46.43 + } + }, + { + "commandType": "dispense", + "key": "aee40692-f291-49f5-bb64-051378a356c7", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "volume": 22, + "labwareId": "111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1", + "wellName": "A7", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 0.5 + } + }, + "flowRate": 46.43 + } + }, + { + "commandType": "dropTip", + "key": "12e5aed2-bcca-4b5b-968b-9cce7d9cb6c7", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "labwareId": "fixedTrash", + "wellName": "A1" + } + }, + { + "commandType": "pickUpTip", + "key": "676d87a5-ed43-48b6-9fd7-b17fff53c880", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "labwareId": "a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1", + "wellName": "F3" + } + }, + { + "commandType": "aspirate", + "key": "5adde3d5-486c-479a-a629-4fd1cd87fa55", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "volume": 22, + "labwareId": "bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1", + "wellName": "A1", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 1 + } + }, + "flowRate": 46.43 + } + }, + { + "commandType": "dispense", + "key": "c21b4b82-8815-4515-9fa4-7097dec1bae2", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "volume": 22, + "labwareId": "111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1", + "wellName": "B7", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 0.5 + } + }, + "flowRate": 46.43 + } + }, + { + "commandType": "dropTip", + "key": "cb2f4bdf-a782-4a68-8bbd-75b65d850d0f", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "labwareId": "fixedTrash", + "wellName": "A1" + } + }, + { + "commandType": "pickUpTip", + "key": "aed095a1-b724-40f8-a1d9-f24820f168ef", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "labwareId": "a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1", + "wellName": "G3" + } + }, + { + "commandType": "aspirate", + "key": "046acfb4-c45e-473c-bfce-7a213e8f2974", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "volume": 22, + "labwareId": "bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1", + "wellName": "A1", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 1 + } + }, + "flowRate": 46.43 + } + }, + { + "commandType": "dispense", + "key": "56c2571e-dde2-4d24-9337-9003e81bee74", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "volume": 22, + "labwareId": "111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1", + "wellName": "C7", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 0.5 + } + }, + "flowRate": 46.43 + } + }, + { + "commandType": "dropTip", + "key": "f1f78069-805a-4db6-90d6-cb81e937d763", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "labwareId": "fixedTrash", + "wellName": "A1" + } + }, + { + "commandType": "pickUpTip", + "key": "daa6b107-d891-4a54-9d68-61fc7a1e3107", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "labwareId": "a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1", + "wellName": "H3" + } + }, + { + "commandType": "aspirate", + "key": "cd45c8ac-3dd7-4d86-b613-9fcd6f7d5542", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "volume": 22, + "labwareId": "bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1", + "wellName": "A1", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 1 + } + }, + "flowRate": 46.43 + } + }, + { + "commandType": "dispense", + "key": "638e754d-5b83-40c0-a6da-3fcdf5da9dda", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "volume": 22, + "labwareId": "111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1", + "wellName": "A8", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 0.5 + } + }, + "flowRate": 46.43 + } + }, + { + "commandType": "dropTip", + "key": "a4fbcb43-71a0-4794-84fe-39a01fb6c5e4", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "labwareId": "fixedTrash", + "wellName": "A1" + } + }, + { + "commandType": "pickUpTip", + "key": "c6d2672b-fcaa-4ff1-a12b-7d9b4fd5d89e", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "labwareId": "a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1", + "wellName": "A4" + } + }, + { + "commandType": "aspirate", + "key": "590a191d-51ab-4915-a1a4-944bb8142356", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "volume": 22, + "labwareId": "bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1", + "wellName": "A1", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 1 + } + }, + "flowRate": 46.43 + } + }, + { + "commandType": "dispense", + "key": "edac7a4f-a283-475c-8c59-bbf91a26c7f3", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "volume": 22, + "labwareId": "111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1", + "wellName": "B8", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 0.5 + } + }, + "flowRate": 46.43 + } + }, + { + "commandType": "dropTip", + "key": "d1f57a8a-040d-4f1d-996a-b8b612ee8fe7", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "labwareId": "fixedTrash", + "wellName": "A1" + } + }, + { + "commandType": "pickUpTip", + "key": "703ed8a5-52d8-45a4-a2e3-965c042b0491", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "labwareId": "a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1", + "wellName": "B4" + } + }, + { + "commandType": "aspirate", + "key": "04316379-9994-4d5b-ac86-99fb532eefb5", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "volume": 22, + "labwareId": "bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1", + "wellName": "A1", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 1 + } + }, + "flowRate": 46.43 + } + }, + { + "commandType": "dispense", + "key": "3a8ea7f4-fc66-4654-ba04-dbd9f221e6a7", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "volume": 22, + "labwareId": "111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1", + "wellName": "C8", + "wellLocation": { + "origin": "bottom", + "offset": { + "z": 0.5 + } + }, + "flowRate": 46.43 + } + }, + { + "commandType": "dropTip", + "key": "09d2d84e-f07b-4459-b0fe-b0216d254008", + "params": { + "pipetteId": "1b766d4d-ba31-42cc-a49a-73e9d8c67aca", + "labwareId": "fixedTrash", + "wellName": "A1" + } + }, + { + "commandType": "thermocycler/closeLid", + "key": "a2fc04dc-f0bf-4b71-a5fb-1334c98197ef", + "params": { + "moduleId": "a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType" + } + }, + { + "commandType": "thermocycler/setTargetBlockTemperature", + "key": "d08d218d-1fc4-40c2-9d19-96adcbb9736e", + "params": { + "moduleId": "a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType", + "celsius": 55 + } + }, + { + "commandType": "thermocycler/waitForBlockTemperature", + "key": "20955b73-7ec4-4170-a05f-329aefefc1ad", + "params": { + "moduleId": "a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType" + } + }, + { + "commandType": "thermocycler/setTargetLidTemperature", + "key": "16621d7f-c322-493b-9d2b-b2a90a685ed0", + "params": { + "moduleId": "a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType", + "celsius": 50 + } + }, + { + "commandType": "thermocycler/waitForLidTemperature", + "key": "50451d2b-8f9a-4101-b6ad-e3308d492276", + "params": { + "moduleId": "a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType" + } + }, + { + "commandType": "heaterShaker/closeLabwareLatch", + "key": "c4232439-eaf7-4e03-a834-35949ebceced", + "params": { + "moduleId": "5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType" + } + }, + { + "commandType": "heaterShaker/setTargetTemperature", + "key": "c055f48a-6e1f-40e7-a254-b1e379c8ff43", + "params": { + "moduleId": "5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType", + "celsius": 55 + } + }, + { + "commandType": "heaterShaker/waitForTemperature", + "key": "be5b2593-b645-4b0f-9593-c0186d5a340d", + "params": { + "moduleId": "5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType" + } + }, + { + "commandType": "heaterShaker/setAndWaitForShakeSpeed", + "key": "bf177287-c03d-4ba6-b8ab-27eb63d58dc4", + "params": { + "moduleId": "5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType", + "rpm": 1000 + } + }, + { + "commandType": "heaterShaker/waitForTemperature", + "key": "a08dddce-7364-44c9-bce7-8e7ecb0f35c2", + "params": { + "moduleId": "5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType" + } + }, + { + "commandType": "magneticModule/engage", + "key": "b1b75cbb-e388-4f3a-aa0f-297ecadf1ae4", + "params": { + "moduleId": "8d4683d0-7a88-4b33-9363-bd3894a71f9a:magneticModuleType", + "height": 12 + } + }, + { + "commandType": "temperatureModule/setTargetTemperature", + "key": "8d2e3b47-7396-4c30-aa08-4b590bcbc967", + "params": { + "moduleId": "b5df8f5c-9fc5-4d45-98c2-0ce6bd218fda:temperatureModuleType", + "celsius": 80 + } + }, + { + "commandType": "heaterShaker/waitForTemperature", + "key": "39aba9eb-2506-4ecf-9c98-adcfd0e7aac6", + "params": { + "moduleId": "5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType" + } + }, + { + "commandType": "heaterShaker/openLabwareLatch", + "key": "675eb8be-6c85-4204-9c87-d7fdd522f580", + "params": { + "moduleId": "5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType" + } + }, + { + "commandType": "heaterShaker/deactivateHeater", + "key": "89eb894c-fbd1-4748-997b-eafc3d2e6feb", + "params": { + "moduleId": "5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType" + } + }, + { + "commandType": "heaterShaker/deactivateShaker", + "key": "7500052e-ea05-4ed7-ac2b-691890d96d5c", + "params": { + "moduleId": "5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType" + } + }, + { + "commandType": "thermocycler/openLid", + "key": "a9f540e3-209d-4dbf-8abc-31dde947f317", + "params": { + "moduleId": "a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType" + } + }, + { + "commandType": "thermocycler/deactivateBlock", + "key": "d029e789-dcc4-4f56-a306-1098b34bce3e", + "params": { + "moduleId": "a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType" + } + }, + { + "commandType": "thermocycler/deactivateLid", + "key": "b8fb1676-e65b-47fd-aa2a-1b447d26820f", + "params": { + "moduleId": "a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType" + } + } + ] +} \ No newline at end of file diff --git a/app-testing/files/protocols/README.md b/app-testing/files/protocols/README.md new file mode 100644 index 00000000000..bcdbfbc9d1d --- /dev/null +++ b/app-testing/files/protocols/README.md @@ -0,0 +1,33 @@ +# File Organization + +## File Naming + +Assuming Gen2 on Pipettes and modules; Include a suffix 1 if not. + +### Naming Convention in order + +- Robot (OT2 or Flex) +- Success (S) or Failure (X) +- PD or API version +- Pipettes (do your best) +- Modules + - GRIP(gripper) + - HS(heater shaker) + - MM(magnetic module) + - MB(magnetic block) + - TC(Thermocycler) + - TM(Temperature Module) +- Overrides `Overrides` or nothing +- Description (don't exceed 25 characters) + +### Examples + +#### .py + +OT2_S_v2_18_None_None_Overrides_BadTypesInRTP.py +OT2_X_v2_16_None_None_TrashBinInStagingAreaCol4.py +Flex_S_v2_15_P1000_96_GRIP_HS_TM_QuickZymoMagbeadRNAExtraction, + +#### .json + +Flex_X_v8_P1000_96_HS_GRIP_TC_TM_GripperCollisionWithTips.json diff --git a/app-testing/files/protocols/generated_protocols/.keepme b/app-testing/files/protocols/generated_protocols/.keepme new file mode 100644 index 00000000000..e69de29bb2d diff --git a/app-testing/files/protocols/json/OT2_P20S_P300M_HS_6_1_HS_WithCollision_Error.json b/app-testing/files/protocols/json/OT2_P20S_P300M_HS_6_1_HS_WithCollision_Error.json deleted file mode 100644 index f6b6efbb38d..00000000000 --- a/app-testing/files/protocols/json/OT2_P20S_P300M_HS_6_1_HS_WithCollision_Error.json +++ /dev/null @@ -1 +0,0 @@ -{"metadata":{"protocolName":"HS Collision","author":"","description":"","created":1660146567413,"lastModified":1660146926908,"category":null,"subcategory":null,"tags":[]},"designerApplication":{"name":"opentrons/protocol-designer","version":"6.0.0","data":{"_internalAppBuildDate":"Mon, 08 Aug 2022 21:31:42 GMT","defaultValues":{"aspirate_mmFromBottom":1,"dispense_mmFromBottom":0.5,"touchTip_mmFromTop":-1,"blowout_mmFromTop":0},"pipetteTiprackAssignments":{"d7e73681-8957-4063-8ce1-38c12373ec39":"opentrons/opentrons_96_tiprack_300ul/1","f5937b23-677d-4cff-bc10-224cf022858c":"opentrons/opentrons_96_tiprack_300ul/1"},"dismissedWarnings":{"form":{},"timeline":{}},"ingredients":{"0":{"name":"Water","displayColor":"#b925ff","description":null,"serialize":false,"liquidGroupId":"0"}},"ingredLocations":{"dbed30a1-d5d7-48b7-82f6-284a20b06118:opentrons/armadillo_96_wellplate_200ul_pcr_full_skirt/1":{"A1":{"0":{"volume":100}},"B1":{"0":{"volume":100}},"C1":{"0":{"volume":100}},"D1":{"0":{"volume":100}},"E1":{"0":{"volume":100}},"F1":{"0":{"volume":100}},"G1":{"0":{"volume":100}},"H1":{"0":{"volume":100}},"A2":{"0":{"volume":100}},"B2":{"0":{"volume":100}},"C2":{"0":{"volume":100}},"D2":{"0":{"volume":100}},"E2":{"0":{"volume":100}},"F2":{"0":{"volume":100}},"G2":{"0":{"volume":100}},"H2":{"0":{"volume":100}},"A3":{"0":{"volume":100}},"B3":{"0":{"volume":100}},"C3":{"0":{"volume":100}},"D3":{"0":{"volume":100}},"E3":{"0":{"volume":100}},"F3":{"0":{"volume":100}},"G3":{"0":{"volume":100}},"H3":{"0":{"volume":100}}}},"savedStepForms":{"__INITIAL_DECK_SETUP_STEP__":{"stepType":"manualIntervention","id":"__INITIAL_DECK_SETUP_STEP__","labwareLocationUpdate":{"fixedTrash":"12","1a8aeb5d-d5df-41b2-a794-ff967118e126:opentrons/opentrons_96_tiprack_300ul/1":"2","59b6af9f-7b2f-4007-a5ef-ef60d38939dc:opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1":"b8a48baa-1ee2-448d-8680-c7126843cbe4:heaterShakerModuleType","3268de61-0657-4a48-8e63-0c3b4bf502a1:opentrons/opentrons_96_tiprack_300ul/1":"4","dbed30a1-d5d7-48b7-82f6-284a20b06118:opentrons/armadillo_96_wellplate_200ul_pcr_full_skirt/1":"5"},"pipetteLocationUpdate":{"d7e73681-8957-4063-8ce1-38c12373ec39":"left","f5937b23-677d-4cff-bc10-224cf022858c":"right"},"moduleLocationUpdate":{"b8a48baa-1ee2-448d-8680-c7126843cbe4:heaterShakerModuleType":"1"}},"a8fa1851-736f-4769-bd5a-7f7bc2dbef89":{"id":"a8fa1851-736f-4769-bd5a-7f7bc2dbef89","stepType":"moveLiquid","stepName":"transfer","stepDetails":"","pipette":"f5937b23-677d-4cff-bc10-224cf022858c","volume":"100","changeTip":"always","path":"single","aspirate_wells_grouped":false,"aspirate_flowRate":null,"aspirate_labware":"dbed30a1-d5d7-48b7-82f6-284a20b06118:opentrons/armadillo_96_wellplate_200ul_pcr_full_skirt/1","aspirate_wells":["A1"],"aspirate_wellOrder_first":"t2b","aspirate_wellOrder_second":"l2r","aspirate_mix_checkbox":false,"aspirate_mix_times":null,"aspirate_mix_volume":null,"aspirate_mmFromBottom":null,"aspirate_touchTip_checkbox":false,"aspirate_touchTip_mmFromBottom":null,"dispense_flowRate":null,"dispense_labware":"59b6af9f-7b2f-4007-a5ef-ef60d38939dc:opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1","dispense_wells":["A2","A12"],"dispense_wellOrder_first":"t2b","dispense_wellOrder_second":"l2r","dispense_mix_checkbox":false,"dispense_mix_times":null,"dispense_mix_volume":null,"dispense_mmFromBottom":null,"dispense_touchTip_checkbox":false,"dispense_touchTip_mmFromBottom":null,"disposalVolume_checkbox":true,"disposalVolume_volume":"20","blowout_checkbox":false,"blowout_location":"fixedTrash","preWetTip":false,"aspirate_airGap_checkbox":false,"aspirate_airGap_volume":"20","aspirate_delay_checkbox":false,"aspirate_delay_mmFromBottom":null,"aspirate_delay_seconds":"1","dispense_airGap_checkbox":false,"dispense_airGap_volume":"20","dispense_delay_checkbox":false,"dispense_delay_seconds":"1","dispense_delay_mmFromBottom":null},"aed6019f-ef5d-4420-8611-f7b4aa7b5d93":{"id":"aed6019f-ef5d-4420-8611-f7b4aa7b5d93","stepType":"heaterShaker","stepName":"heater-shaker","stepDetails":"","moduleId":"b8a48baa-1ee2-448d-8680-c7126843cbe4:heaterShakerModuleType","setHeaterShakerTemperature":null,"targetHeaterShakerTemperature":null,"targetSpeed":null,"setShake":null,"latchOpen":false,"heaterShakerSetTimer":null,"heaterShakerTimerMinutes":null,"heaterShakerTimerSeconds":null}},"orderedStepIds":["aed6019f-ef5d-4420-8611-f7b4aa7b5d93","a8fa1851-736f-4769-bd5a-7f7bc2dbef89"]}},"robot":{"model":"OT-2 Standard","deckId":"ot2_standard"},"pipettes":{"d7e73681-8957-4063-8ce1-38c12373ec39":{"name":"p300_single_gen2"},"f5937b23-677d-4cff-bc10-224cf022858c":{"name":"p300_multi_gen2"}},"labware":{"fixedTrash":{"displayName":"Trash","definitionId":"opentrons/opentrons_1_trash_1100ml_fixed/1"},"1a8aeb5d-d5df-41b2-a794-ff967118e126:opentrons/opentrons_96_tiprack_300ul/1":{"displayName":"Opentrons 96 Tip Rack 300 µL","definitionId":"opentrons/opentrons_96_tiprack_300ul/1"},"59b6af9f-7b2f-4007-a5ef-ef60d38939dc:opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1":{"displayName":"H/S","definitionId":"opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1"},"3268de61-0657-4a48-8e63-0c3b4bf502a1:opentrons/opentrons_96_tiprack_300ul/1":{"displayName":"Opentrons 96 Tip Rack 300 µL (1)","definitionId":"opentrons/opentrons_96_tiprack_300ul/1"},"dbed30a1-d5d7-48b7-82f6-284a20b06118:opentrons/armadillo_96_wellplate_200ul_pcr_full_skirt/1":{"displayName":"1","definitionId":"opentrons/armadillo_96_wellplate_200ul_pcr_full_skirt/1"}},"liquids":{"0":{"displayName":"Water","description":"","displayColor":"#b925ff"}},"labwareDefinitions":{"opentrons/opentrons_96_tiprack_300ul/1":{"ordering":[["A1","B1","C1","D1","E1","F1","G1","H1"],["A2","B2","C2","D2","E2","F2","G2","H2"],["A3","B3","C3","D3","E3","F3","G3","H3"],["A4","B4","C4","D4","E4","F4","G4","H4"],["A5","B5","C5","D5","E5","F5","G5","H5"],["A6","B6","C6","D6","E6","F6","G6","H6"],["A7","B7","C7","D7","E7","F7","G7","H7"],["A8","B8","C8","D8","E8","F8","G8","H8"],["A9","B9","C9","D9","E9","F9","G9","H9"],["A10","B10","C10","D10","E10","F10","G10","H10"],["A11","B11","C11","D11","E11","F11","G11","H11"],["A12","B12","C12","D12","E12","F12","G12","H12"]],"brand":{"brand":"Opentrons","brandId":[],"links":["https://shop.opentrons.com/collections/opentrons-tips/products/opentrons-300ul-tips"]},"metadata":{"displayName":"Opentrons 96 Tip Rack 300 µL","displayCategory":"tipRack","displayVolumeUnits":"µL","tags":[]},"dimensions":{"xDimension":127.76,"yDimension":85.48,"zDimension":64.49},"wells":{"A1":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":14.38,"y":74.24,"z":5.39},"B1":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":14.38,"y":65.24,"z":5.39},"C1":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":14.38,"y":56.24,"z":5.39},"D1":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":14.38,"y":47.24,"z":5.39},"E1":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":14.38,"y":38.24,"z":5.39},"F1":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":14.38,"y":29.24,"z":5.39},"G1":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":14.38,"y":20.24,"z":5.39},"H1":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":14.38,"y":11.24,"z":5.39},"A2":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":23.38,"y":74.24,"z":5.39},"B2":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":23.38,"y":65.24,"z":5.39},"C2":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":23.38,"y":56.24,"z":5.39},"D2":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":23.38,"y":47.24,"z":5.39},"E2":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":23.38,"y":38.24,"z":5.39},"F2":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":23.38,"y":29.24,"z":5.39},"G2":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":23.38,"y":20.24,"z":5.39},"H2":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":23.38,"y":11.24,"z":5.39},"A3":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":32.38,"y":74.24,"z":5.39},"B3":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":32.38,"y":65.24,"z":5.39},"C3":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":32.38,"y":56.24,"z":5.39},"D3":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":32.38,"y":47.24,"z":5.39},"E3":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":32.38,"y":38.24,"z":5.39},"F3":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":32.38,"y":29.24,"z":5.39},"G3":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":32.38,"y":20.24,"z":5.39},"H3":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":32.38,"y":11.24,"z":5.39},"A4":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":41.38,"y":74.24,"z":5.39},"B4":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":41.38,"y":65.24,"z":5.39},"C4":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":41.38,"y":56.24,"z":5.39},"D4":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":41.38,"y":47.24,"z":5.39},"E4":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":41.38,"y":38.24,"z":5.39},"F4":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":41.38,"y":29.24,"z":5.39},"G4":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":41.38,"y":20.24,"z":5.39},"H4":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":41.38,"y":11.24,"z":5.39},"A5":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":50.38,"y":74.24,"z":5.39},"B5":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":50.38,"y":65.24,"z":5.39},"C5":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":50.38,"y":56.24,"z":5.39},"D5":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":50.38,"y":47.24,"z":5.39},"E5":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":50.38,"y":38.24,"z":5.39},"F5":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":50.38,"y":29.24,"z":5.39},"G5":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":50.38,"y":20.24,"z":5.39},"H5":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":50.38,"y":11.24,"z":5.39},"A6":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":59.38,"y":74.24,"z":5.39},"B6":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":59.38,"y":65.24,"z":5.39},"C6":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":59.38,"y":56.24,"z":5.39},"D6":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":59.38,"y":47.24,"z":5.39},"E6":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":59.38,"y":38.24,"z":5.39},"F6":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":59.38,"y":29.24,"z":5.39},"G6":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":59.38,"y":20.24,"z":5.39},"H6":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":59.38,"y":11.24,"z":5.39},"A7":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":68.38,"y":74.24,"z":5.39},"B7":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":68.38,"y":65.24,"z":5.39},"C7":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":68.38,"y":56.24,"z":5.39},"D7":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":68.38,"y":47.24,"z":5.39},"E7":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":68.38,"y":38.24,"z":5.39},"F7":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":68.38,"y":29.24,"z":5.39},"G7":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":68.38,"y":20.24,"z":5.39},"H7":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":68.38,"y":11.24,"z":5.39},"A8":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":77.38,"y":74.24,"z":5.39},"B8":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":77.38,"y":65.24,"z":5.39},"C8":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":77.38,"y":56.24,"z":5.39},"D8":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":77.38,"y":47.24,"z":5.39},"E8":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":77.38,"y":38.24,"z":5.39},"F8":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":77.38,"y":29.24,"z":5.39},"G8":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":77.38,"y":20.24,"z":5.39},"H8":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":77.38,"y":11.24,"z":5.39},"A9":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":86.38,"y":74.24,"z":5.39},"B9":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":86.38,"y":65.24,"z":5.39},"C9":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":86.38,"y":56.24,"z":5.39},"D9":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":86.38,"y":47.24,"z":5.39},"E9":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":86.38,"y":38.24,"z":5.39},"F9":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":86.38,"y":29.24,"z":5.39},"G9":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":86.38,"y":20.24,"z":5.39},"H9":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":86.38,"y":11.24,"z":5.39},"A10":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":95.38,"y":74.24,"z":5.39},"B10":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":95.38,"y":65.24,"z":5.39},"C10":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":95.38,"y":56.24,"z":5.39},"D10":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":95.38,"y":47.24,"z":5.39},"E10":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":95.38,"y":38.24,"z":5.39},"F10":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":95.38,"y":29.24,"z":5.39},"G10":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":95.38,"y":20.24,"z":5.39},"H10":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":95.38,"y":11.24,"z":5.39},"A11":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":104.38,"y":74.24,"z":5.39},"B11":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":104.38,"y":65.24,"z":5.39},"C11":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":104.38,"y":56.24,"z":5.39},"D11":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":104.38,"y":47.24,"z":5.39},"E11":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":104.38,"y":38.24,"z":5.39},"F11":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":104.38,"y":29.24,"z":5.39},"G11":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":104.38,"y":20.24,"z":5.39},"H11":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":104.38,"y":11.24,"z":5.39},"A12":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":113.38,"y":74.24,"z":5.39},"B12":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":113.38,"y":65.24,"z":5.39},"C12":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":113.38,"y":56.24,"z":5.39},"D12":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":113.38,"y":47.24,"z":5.39},"E12":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":113.38,"y":38.24,"z":5.39},"F12":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":113.38,"y":29.24,"z":5.39},"G12":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":113.38,"y":20.24,"z":5.39},"H12":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":113.38,"y":11.24,"z":5.39}},"groups":[{"metadata":{},"wells":["A1","B1","C1","D1","E1","F1","G1","H1","A2","B2","C2","D2","E2","F2","G2","H2","A3","B3","C3","D3","E3","F3","G3","H3","A4","B4","C4","D4","E4","F4","G4","H4","A5","B5","C5","D5","E5","F5","G5","H5","A6","B6","C6","D6","E6","F6","G6","H6","A7","B7","C7","D7","E7","F7","G7","H7","A8","B8","C8","D8","E8","F8","G8","H8","A9","B9","C9","D9","E9","F9","G9","H9","A10","B10","C10","D10","E10","F10","G10","H10","A11","B11","C11","D11","E11","F11","G11","H11","A12","B12","C12","D12","E12","F12","G12","H12"]}],"parameters":{"format":"96Standard","isTiprack":true,"tipLength":59.3,"tipOverlap":7.47,"isMagneticModuleCompatible":false,"loadName":"opentrons_96_tiprack_300ul"},"namespace":"opentrons","version":1,"schemaVersion":2,"cornerOffsetFromSlot":{"x":0,"y":0,"z":0}},"opentrons/opentrons_1_trash_1100ml_fixed/1":{"ordering":[["A1"]],"metadata":{"displayCategory":"trash","displayVolumeUnits":"mL","displayName":"Opentrons Fixed Trash","tags":[]},"schemaVersion":2,"version":1,"namespace":"opentrons","dimensions":{"xDimension":172.86,"yDimension":165.86,"zDimension":82},"parameters":{"format":"trash","isTiprack":false,"loadName":"opentrons_1_trash_1100ml_fixed","isMagneticModuleCompatible":false,"quirks":["fixedTrash","centerMultichannelOnWells","touchTipDisabled"]},"wells":{"A1":{"shape":"rectangular","yDimension":165.67,"xDimension":107.11,"totalLiquidVolume":1100000,"depth":0,"x":82.84,"y":80,"z":82}},"brand":{"brand":"Opentrons"},"groups":[{"wells":["A1"],"metadata":{}}],"cornerOffsetFromSlot":{"x":0,"y":0,"z":0}},"opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1":{"ordering":[["A1","B1","C1","D1","E1","F1","G1","H1"],["A2","B2","C2","D2","E2","F2","G2","H2"],["A3","B3","C3","D3","E3","F3","G3","H3"],["A4","B4","C4","D4","E4","F4","G4","H4"],["A5","B5","C5","D5","E5","F5","G5","H5"],["A6","B6","C6","D6","E6","F6","G6","H6"],["A7","B7","C7","D7","E7","F7","G7","H7"],["A8","B8","C8","D8","E8","F8","G8","H8"],["A9","B9","C9","D9","E9","F9","G9","H9"],["A10","B10","C10","D10","E10","F10","G10","H10"],["A11","B11","C11","D11","E11","F11","G11","H11"],["A12","B12","C12","D12","E12","F12","G12","H12"]],"brand":{"brand":"Opentrons","brandId":[],"links":[]},"metadata":{"displayName":"Opentrons 96 Deep Well Adapter with NEST Deep Well Plate 2 mL","displayCategory":"aluminumBlock","displayVolumeUnits":"µL","tags":[]},"dimensions":{"xDimension":127.6,"yDimension":85.3,"zDimension":42.25},"wells":{"A1":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":14.3,"y":74.15,"z":4.25},"B1":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":14.3,"y":65.15,"z":4.25},"C1":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":14.3,"y":56.15,"z":4.25},"D1":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":14.3,"y":47.15,"z":4.25},"E1":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":14.3,"y":38.15,"z":4.25},"F1":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":14.3,"y":29.15,"z":4.25},"G1":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":14.3,"y":20.15,"z":4.25},"H1":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":14.3,"y":11.15,"z":4.25},"A2":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":23.3,"y":74.15,"z":4.25},"B2":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":23.3,"y":65.15,"z":4.25},"C2":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":23.3,"y":56.15,"z":4.25},"D2":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":23.3,"y":47.15,"z":4.25},"E2":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":23.3,"y":38.15,"z":4.25},"F2":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":23.3,"y":29.15,"z":4.25},"G2":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":23.3,"y":20.15,"z":4.25},"H2":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":23.3,"y":11.15,"z":4.25},"A3":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":32.3,"y":74.15,"z":4.25},"B3":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":32.3,"y":65.15,"z":4.25},"C3":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":32.3,"y":56.15,"z":4.25},"D3":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":32.3,"y":47.15,"z":4.25},"E3":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":32.3,"y":38.15,"z":4.25},"F3":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":32.3,"y":29.15,"z":4.25},"G3":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":32.3,"y":20.15,"z":4.25},"H3":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":32.3,"y":11.15,"z":4.25},"A4":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":41.3,"y":74.15,"z":4.25},"B4":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":41.3,"y":65.15,"z":4.25},"C4":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":41.3,"y":56.15,"z":4.25},"D4":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":41.3,"y":47.15,"z":4.25},"E4":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":41.3,"y":38.15,"z":4.25},"F4":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":41.3,"y":29.15,"z":4.25},"G4":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":41.3,"y":20.15,"z":4.25},"H4":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":41.3,"y":11.15,"z":4.25},"A5":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":50.3,"y":74.15,"z":4.25},"B5":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":50.3,"y":65.15,"z":4.25},"C5":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":50.3,"y":56.15,"z":4.25},"D5":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":50.3,"y":47.15,"z":4.25},"E5":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":50.3,"y":38.15,"z":4.25},"F5":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":50.3,"y":29.15,"z":4.25},"G5":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":50.3,"y":20.15,"z":4.25},"H5":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":50.3,"y":11.15,"z":4.25},"A6":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":59.3,"y":74.15,"z":4.25},"B6":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":59.3,"y":65.15,"z":4.25},"C6":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":59.3,"y":56.15,"z":4.25},"D6":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":59.3,"y":47.15,"z":4.25},"E6":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":59.3,"y":38.15,"z":4.25},"F6":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":59.3,"y":29.15,"z":4.25},"G6":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":59.3,"y":20.15,"z":4.25},"H6":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":59.3,"y":11.15,"z":4.25},"A7":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":68.3,"y":74.15,"z":4.25},"B7":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":68.3,"y":65.15,"z":4.25},"C7":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":68.3,"y":56.15,"z":4.25},"D7":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":68.3,"y":47.15,"z":4.25},"E7":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":68.3,"y":38.15,"z":4.25},"F7":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":68.3,"y":29.15,"z":4.25},"G7":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":68.3,"y":20.15,"z":4.25},"H7":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":68.3,"y":11.15,"z":4.25},"A8":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":77.3,"y":74.15,"z":4.25},"B8":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":77.3,"y":65.15,"z":4.25},"C8":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":77.3,"y":56.15,"z":4.25},"D8":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":77.3,"y":47.15,"z":4.25},"E8":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":77.3,"y":38.15,"z":4.25},"F8":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":77.3,"y":29.15,"z":4.25},"G8":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":77.3,"y":20.15,"z":4.25},"H8":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":77.3,"y":11.15,"z":4.25},"A9":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":86.3,"y":74.15,"z":4.25},"B9":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":86.3,"y":65.15,"z":4.25},"C9":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":86.3,"y":56.15,"z":4.25},"D9":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":86.3,"y":47.15,"z":4.25},"E9":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":86.3,"y":38.15,"z":4.25},"F9":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":86.3,"y":29.15,"z":4.25},"G9":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":86.3,"y":20.15,"z":4.25},"H9":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":86.3,"y":11.15,"z":4.25},"A10":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":95.3,"y":74.15,"z":4.25},"B10":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":95.3,"y":65.15,"z":4.25},"C10":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":95.3,"y":56.15,"z":4.25},"D10":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":95.3,"y":47.15,"z":4.25},"E10":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":95.3,"y":38.15,"z":4.25},"F10":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":95.3,"y":29.15,"z":4.25},"G10":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":95.3,"y":20.15,"z":4.25},"H10":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":95.3,"y":11.15,"z":4.25},"A11":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":104.3,"y":74.15,"z":4.25},"B11":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":104.3,"y":65.15,"z":4.25},"C11":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":104.3,"y":56.15,"z":4.25},"D11":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":104.3,"y":47.15,"z":4.25},"E11":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":104.3,"y":38.15,"z":4.25},"F11":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":104.3,"y":29.15,"z":4.25},"G11":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":104.3,"y":20.15,"z":4.25},"H11":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":104.3,"y":11.15,"z":4.25},"A12":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":113.3,"y":74.15,"z":4.25},"B12":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":113.3,"y":65.15,"z":4.25},"C12":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":113.3,"y":56.15,"z":4.25},"D12":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":113.3,"y":47.15,"z":4.25},"E12":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":113.3,"y":38.15,"z":4.25},"F12":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":113.3,"y":29.15,"z":4.25},"G12":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":113.3,"y":20.15,"z":4.25},"H12":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":113.3,"y":11.15,"z":4.25}},"groups":[{"metadata":{"displayName":"NEST 96 Deepwell Plate 2mL","displayCategory":"wellPlate","wellBottomShape":"v"},"brand":{"brand":"NEST","brandId":["503501","503001"],"links":["https://www.nest-biotech.com/deep-well-plates/59253726.html"]},"wells":["A1","B1","C1","D1","E1","F1","G1","H1","A2","B2","C2","D2","E2","F2","G2","H2","A3","B3","C3","D3","E3","F3","G3","H3","A4","B4","C4","D4","E4","F4","G4","H4","A5","B5","C5","D5","E5","F5","G5","H5","A6","B6","C6","D6","E6","F6","G6","H6","A7","B7","C7","D7","E7","F7","G7","H7","A8","B8","C8","D8","E8","F8","G8","H8","A9","B9","C9","D9","E9","F9","G9","H9","A10","B10","C10","D10","E10","F10","G10","H10","A11","B11","C11","D11","E11","F11","G11","H11","A12","B12","C12","D12","E12","F12","G12","H12"]}],"parameters":{"format":"96Standard","quirks":[],"isTiprack":false,"isMagneticModuleCompatible":false,"loadName":"opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep"},"namespace":"opentrons","version":1,"schemaVersion":2,"cornerOffsetFromSlot":{"x":0,"y":0,"z":0}},"opentrons/armadillo_96_wellplate_200ul_pcr_full_skirt/1":{"namespace":"opentrons","version":1,"schemaVersion":2,"parameters":{"loadName":"armadillo_96_wellplate_200ul_pcr_full_skirt","format":"96Standard","isTiprack":false,"isMagneticModuleCompatible":true},"metadata":{"displayName":"Armadillo 96 Well Plate 200 µL PCR Full Skirt","displayCategory":"wellPlate","displayVolumeUnits":"µL","tags":[]},"brand":{"brand":"Thermo Scientific","brandId":["AB2396"],"links":["https://www.fishersci.com/shop/products/armadillo-96-well-pcr-plate-1/AB2396"]},"dimensions":{"xDimension":127.76,"yDimension":85.48,"zDimension":16},"cornerOffsetFromSlot":{"x":0,"y":0,"z":0},"ordering":[["A1","B1","C1","D1","E1","F1","G1","H1"],["A2","B2","C2","D2","E2","F2","G2","H2"],["A3","B3","C3","D3","E3","F3","G3","H3"],["A4","B4","C4","D4","E4","F4","G4","H4"],["A5","B5","C5","D5","E5","F5","G5","H5"],["A6","B6","C6","D6","E6","F6","G6","H6"],["A7","B7","C7","D7","E7","F7","G7","H7"],["A8","B8","C8","D8","E8","F8","G8","H8"],["A9","B9","C9","D9","E9","F9","G9","H9"],["A10","B10","C10","D10","E10","F10","G10","H10"],["A11","B11","C11","D11","E11","F11","G11","H11"],["A12","B12","C12","D12","E12","F12","G12","H12"]],"wells":{"A1":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":14.38,"y":74.24,"z":1.05},"B1":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":14.38,"y":65.24,"z":1.05},"C1":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":14.38,"y":56.24,"z":1.05},"D1":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":14.38,"y":47.24,"z":1.05},"E1":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":14.38,"y":38.24,"z":1.05},"F1":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":14.38,"y":29.24,"z":1.05},"G1":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":14.38,"y":20.24,"z":1.05},"H1":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":14.38,"y":11.24,"z":1.05},"A2":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":23.38,"y":74.24,"z":1.05},"B2":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":23.38,"y":65.24,"z":1.05},"C2":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":23.38,"y":56.24,"z":1.05},"D2":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":23.38,"y":47.24,"z":1.05},"E2":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":23.38,"y":38.24,"z":1.05},"F2":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":23.38,"y":29.24,"z":1.05},"G2":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":23.38,"y":20.24,"z":1.05},"H2":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":23.38,"y":11.24,"z":1.05},"A3":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":32.38,"y":74.24,"z":1.05},"B3":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":32.38,"y":65.24,"z":1.05},"C3":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":32.38,"y":56.24,"z":1.05},"D3":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":32.38,"y":47.24,"z":1.05},"E3":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":32.38,"y":38.24,"z":1.05},"F3":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":32.38,"y":29.24,"z":1.05},"G3":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":32.38,"y":20.24,"z":1.05},"H3":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":32.38,"y":11.24,"z":1.05},"A4":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":41.38,"y":74.24,"z":1.05},"B4":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":41.38,"y":65.24,"z":1.05},"C4":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":41.38,"y":56.24,"z":1.05},"D4":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":41.38,"y":47.24,"z":1.05},"E4":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":41.38,"y":38.24,"z":1.05},"F4":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":41.38,"y":29.24,"z":1.05},"G4":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":41.38,"y":20.24,"z":1.05},"H4":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":41.38,"y":11.24,"z":1.05},"A5":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":50.38,"y":74.24,"z":1.05},"B5":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":50.38,"y":65.24,"z":1.05},"C5":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":50.38,"y":56.24,"z":1.05},"D5":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":50.38,"y":47.24,"z":1.05},"E5":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":50.38,"y":38.24,"z":1.05},"F5":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":50.38,"y":29.24,"z":1.05},"G5":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":50.38,"y":20.24,"z":1.05},"H5":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":50.38,"y":11.24,"z":1.05},"A6":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":59.38,"y":74.24,"z":1.05},"B6":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":59.38,"y":65.24,"z":1.05},"C6":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":59.38,"y":56.24,"z":1.05},"D6":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":59.38,"y":47.24,"z":1.05},"E6":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":59.38,"y":38.24,"z":1.05},"F6":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":59.38,"y":29.24,"z":1.05},"G6":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":59.38,"y":20.24,"z":1.05},"H6":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":59.38,"y":11.24,"z":1.05},"A7":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":68.38,"y":74.24,"z":1.05},"B7":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":68.38,"y":65.24,"z":1.05},"C7":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":68.38,"y":56.24,"z":1.05},"D7":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":68.38,"y":47.24,"z":1.05},"E7":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":68.38,"y":38.24,"z":1.05},"F7":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":68.38,"y":29.24,"z":1.05},"G7":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":68.38,"y":20.24,"z":1.05},"H7":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":68.38,"y":11.24,"z":1.05},"A8":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":77.38,"y":74.24,"z":1.05},"B8":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":77.38,"y":65.24,"z":1.05},"C8":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":77.38,"y":56.24,"z":1.05},"D8":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":77.38,"y":47.24,"z":1.05},"E8":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":77.38,"y":38.24,"z":1.05},"F8":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":77.38,"y":29.24,"z":1.05},"G8":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":77.38,"y":20.24,"z":1.05},"H8":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":77.38,"y":11.24,"z":1.05},"A9":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":86.38,"y":74.24,"z":1.05},"B9":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":86.38,"y":65.24,"z":1.05},"C9":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":86.38,"y":56.24,"z":1.05},"D9":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":86.38,"y":47.24,"z":1.05},"E9":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":86.38,"y":38.24,"z":1.05},"F9":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":86.38,"y":29.24,"z":1.05},"G9":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":86.38,"y":20.24,"z":1.05},"H9":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":86.38,"y":11.24,"z":1.05},"A10":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":95.38,"y":74.24,"z":1.05},"B10":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":95.38,"y":65.24,"z":1.05},"C10":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":95.38,"y":56.24,"z":1.05},"D10":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":95.38,"y":47.24,"z":1.05},"E10":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":95.38,"y":38.24,"z":1.05},"F10":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":95.38,"y":29.24,"z":1.05},"G10":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":95.38,"y":20.24,"z":1.05},"H10":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":95.38,"y":11.24,"z":1.05},"A11":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":104.38,"y":74.24,"z":1.05},"B11":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":104.38,"y":65.24,"z":1.05},"C11":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":104.38,"y":56.24,"z":1.05},"D11":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":104.38,"y":47.24,"z":1.05},"E11":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":104.38,"y":38.24,"z":1.05},"F11":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":104.38,"y":29.24,"z":1.05},"G11":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":104.38,"y":20.24,"z":1.05},"H11":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":104.38,"y":11.24,"z":1.05},"A12":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":113.38,"y":74.24,"z":1.05},"B12":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":113.38,"y":65.24,"z":1.05},"C12":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":113.38,"y":56.24,"z":1.05},"D12":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":113.38,"y":47.24,"z":1.05},"E12":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":113.38,"y":38.24,"z":1.05},"F12":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":113.38,"y":29.24,"z":1.05},"G12":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":113.38,"y":20.24,"z":1.05},"H12":{"depth":14.95,"totalLiquidVolume":200,"shape":"circular","diameter":5.5,"x":113.38,"y":11.24,"z":1.05}},"groups":[{"metadata":{"wellBottomShape":"v"},"wells":["A1","B1","C1","D1","E1","F1","G1","H1","A2","B2","C2","D2","E2","F2","G2","H2","A3","B3","C3","D3","E3","F3","G3","H3","A4","B4","C4","D4","E4","F4","G4","H4","A5","B5","C5","D5","E5","F5","G5","H5","A6","B6","C6","D6","E6","F6","G6","H6","A7","B7","C7","D7","E7","F7","G7","H7","A8","B8","C8","D8","E8","F8","G8","H8","A9","B9","C9","D9","E9","F9","G9","H9","A10","B10","C10","D10","E10","F10","G10","H10","A11","B11","C11","D11","E11","F11","G11","H11","A12","B12","C12","D12","E12","F12","G12","H12"]}]}},"$otSharedSchema":"#/protocol/schemas/6","schemaVersion":6,"modules":{"b8a48baa-1ee2-448d-8680-c7126843cbe4:heaterShakerModuleType":{"model":"heaterShakerModuleV1"}},"commands":[{"key":"371f4a86-b9a5-4bc0-8bdd-d28460087c31","commandType":"loadPipette","params":{"pipetteId":"d7e73681-8957-4063-8ce1-38c12373ec39","mount":"left"}},{"key":"00c0d791-6167-4a8b-8822-0482a6229976","commandType":"loadPipette","params":{"pipetteId":"f5937b23-677d-4cff-bc10-224cf022858c","mount":"right"}},{"key":"e3a5093f-bfb7-433b-a064-05de0c322c35","commandType":"loadModule","params":{"moduleId":"b8a48baa-1ee2-448d-8680-c7126843cbe4:heaterShakerModuleType","location":{"slotName":"1"}}},{"key":"1f08132e-50c9-457b-b543-1d3318c5d075","commandType":"loadLabware","params":{"labwareId":"1a8aeb5d-d5df-41b2-a794-ff967118e126:opentrons/opentrons_96_tiprack_300ul/1","location":{"slotName":"2"}}},{"key":"f6ad95f9-6d54-453e-8630-50ee166deb5a","commandType":"loadLabware","params":{"labwareId":"59b6af9f-7b2f-4007-a5ef-ef60d38939dc:opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1","location":{"moduleId":"b8a48baa-1ee2-448d-8680-c7126843cbe4:heaterShakerModuleType"}}},{"key":"83b274d2-cbf1-4913-95dd-2c29e196983c","commandType":"loadLabware","params":{"labwareId":"3268de61-0657-4a48-8e63-0c3b4bf502a1:opentrons/opentrons_96_tiprack_300ul/1","location":{"slotName":"4"}}},{"key":"10a1df55-87a4-4eb3-ba1c-4e9b6e4ed3e5","commandType":"loadLabware","params":{"labwareId":"dbed30a1-d5d7-48b7-82f6-284a20b06118:opentrons/armadillo_96_wellplate_200ul_pcr_full_skirt/1","location":{"slotName":"5"}}},{"commandType":"loadLiquid","key":"99f4bd4a-9385-45cf-b57c-55a619e9b961","params":{"liquidId":"0","labwareId":"dbed30a1-d5d7-48b7-82f6-284a20b06118:opentrons/armadillo_96_wellplate_200ul_pcr_full_skirt/1","volumeByWell":{"A1":100,"B1":100,"C1":100,"D1":100,"E1":100,"F1":100,"G1":100,"H1":100,"A2":100,"B2":100,"C2":100,"D2":100,"E2":100,"F2":100,"G2":100,"H2":100,"A3":100,"B3":100,"C3":100,"D3":100,"E3":100,"F3":100,"G3":100,"H3":100}}},{"commandType":"heaterShaker/closeLabwareLatch","key":"e5e36a96-61c3-4d73-98a7-17aeb667b727","params":{"moduleId":"b8a48baa-1ee2-448d-8680-c7126843cbe4:heaterShakerModuleType"}},{"commandType":"heaterShaker/deactivateHeater","key":"fe2e39c4-5245-465a-8df8-33096913a07d","params":{"moduleId":"b8a48baa-1ee2-448d-8680-c7126843cbe4:heaterShakerModuleType"}},{"commandType":"heaterShaker/deactivateShaker","key":"b214ab6f-85af-46be-85ea-ec7fbde9cf15","params":{"moduleId":"b8a48baa-1ee2-448d-8680-c7126843cbe4:heaterShakerModuleType"}}]} \ No newline at end of file diff --git a/app-testing/files/protocols/json/OT2_P300M_P20S_MM_HS_TD_TC_6_1_AllMods_Error.json b/app-testing/files/protocols/json/OT2_P300M_P20S_MM_HS_TD_TC_6_1_AllMods_Error.json deleted file mode 100644 index 39ce0edc176..00000000000 --- a/app-testing/files/protocols/json/OT2_P300M_P20S_MM_HS_TD_TC_6_1_AllMods_Error.json +++ /dev/null @@ -1 +0,0 @@ -{"metadata":{"protocolName":"All mods","author":"","description":"","created":1660661146739,"lastModified":1660661894787,"category":null,"subcategory":null,"tags":[]},"designerApplication":{"name":"opentrons/protocol-designer","version":"6.0.0","data":{"_internalAppBuildDate":"Mon, 08 Aug 2022 21:31:42 GMT","defaultValues":{"aspirate_mmFromBottom":1,"dispense_mmFromBottom":0.5,"touchTip_mmFromTop":-1,"blowout_mmFromTop":0},"pipetteTiprackAssignments":{"9467efbc-2ad4-40eb-bc05-91c78fd48be2":"opentrons/opentrons_96_tiprack_300ul/1","1b766d4d-ba31-42cc-a49a-73e9d8c67aca":"opentrons/opentrons_96_tiprack_300ul/1"},"dismissedWarnings":{"form":{},"timeline":{}},"ingredients":{"0":{"name":"L1","displayColor":"#b925ff","description":null,"serialize":false,"liquidGroupId":"0"},"1":{"name":"L2","displayColor":"#ffd600","description":null,"serialize":false,"liquidGroupId":"1"}},"ingredLocations":{"bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1":{"A1":{"0":{"volume":29000}}},"01ab8b91-996c-41a2-a11e-57719913979e:opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1":{"A1":{"1":{"volume":300}},"B1":{"1":{"volume":300}},"C1":{"1":{"volume":300}},"D1":{"1":{"volume":300}},"A2":{"1":{"volume":300}},"B2":{"1":{"volume":300}},"C2":{"1":{"volume":300}},"D2":{"1":{"volume":300}}},"0d460f8a-2163-4eb7-8f48-5c382604971a:opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1":{"A1":{"1":{"volume":20}},"B1":{"1":{"volume":20}},"C1":{"1":{"volume":20}},"D1":{"1":{"volume":20}},"E1":{"1":{"volume":20}},"F1":{"1":{"volume":20}},"G1":{"1":{"volume":20}},"H1":{"1":{"volume":20}},"A2":{"1":{"volume":20}},"B2":{"1":{"volume":20}},"C2":{"1":{"volume":20}},"D2":{"1":{"volume":20}},"E2":{"1":{"volume":20}},"F2":{"1":{"volume":20}},"G2":{"1":{"volume":20}},"H2":{"1":{"volume":20}},"A3":{"1":{"volume":20}},"B3":{"1":{"volume":20}},"C3":{"1":{"volume":20}},"D3":{"1":{"volume":20}},"E3":{"1":{"volume":20}},"F3":{"1":{"volume":20}},"G3":{"1":{"volume":20}},"H3":{"1":{"volume":20}}},"111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1":{"A1":{"1":{"volume":100}},"B1":{"1":{"volume":100}},"C1":{"1":{"volume":100}},"D1":{"1":{"volume":100}},"E1":{"1":{"volume":100}},"F1":{"1":{"volume":100}},"G1":{"1":{"volume":100}},"H1":{"1":{"volume":100}},"A2":{"1":{"volume":100}},"B2":{"1":{"volume":100}},"C2":{"1":{"volume":100}},"D2":{"1":{"volume":100}},"E2":{"1":{"volume":100}},"F2":{"1":{"volume":100}},"G2":{"1":{"volume":100}},"H2":{"1":{"volume":100}},"A3":{"1":{"volume":100}},"B3":{"1":{"volume":100}},"C3":{"1":{"volume":100}},"D3":{"1":{"volume":100}},"E3":{"1":{"volume":100}},"F3":{"1":{"volume":100}},"G3":{"1":{"volume":100}},"H3":{"1":{"volume":100}},"A4":{"1":{"volume":100}},"B4":{"1":{"volume":100}},"C4":{"1":{"volume":100}},"D4":{"1":{"volume":100}},"E4":{"1":{"volume":100}},"F4":{"1":{"volume":100}},"G4":{"1":{"volume":100}},"H4":{"1":{"volume":100}},"A5":{"1":{"volume":100}},"B5":{"1":{"volume":100}},"C5":{"1":{"volume":100}},"D5":{"1":{"volume":100}},"E5":{"1":{"volume":100}},"F5":{"1":{"volume":100}},"G5":{"1":{"volume":100}},"H5":{"1":{"volume":100}},"A6":{"1":{"volume":100}},"B6":{"1":{"volume":100}},"C6":{"1":{"volume":100}},"D6":{"1":{"volume":100}},"E6":{"1":{"volume":100}},"F6":{"1":{"volume":100}},"G6":{"1":{"volume":100}},"H6":{"1":{"volume":100}}},"32e39cda-1d1d-4e0d-b933-b94cf464e29a:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1":{"A1":{"1":{"volume":100}},"B1":{"1":{"volume":100}},"C1":{"1":{"volume":100}},"D1":{"1":{"volume":100}},"E1":{"1":{"volume":100}},"F1":{"1":{"volume":100}},"G1":{"1":{"volume":100}},"H1":{"1":{"volume":100}},"A2":{"1":{"volume":100}},"B2":{"1":{"volume":100}},"C2":{"1":{"volume":100}},"D2":{"1":{"volume":100}},"E2":{"1":{"volume":100}},"F2":{"1":{"volume":100}},"G2":{"1":{"volume":100}},"H2":{"1":{"volume":100}},"A3":{"1":{"volume":100}},"B3":{"1":{"volume":100}},"C3":{"1":{"volume":100}},"D3":{"1":{"volume":100}},"E3":{"1":{"volume":100}},"F3":{"1":{"volume":100}},"G3":{"1":{"volume":100}},"H3":{"1":{"volume":100}},"A4":{"1":{"volume":100}},"B4":{"1":{"volume":100}},"C4":{"1":{"volume":100}},"D4":{"1":{"volume":100}},"E4":{"1":{"volume":100}},"F4":{"1":{"volume":100}},"G4":{"1":{"volume":100}},"H4":{"1":{"volume":100}},"A5":{"1":{"volume":100}},"B5":{"1":{"volume":100}},"C5":{"1":{"volume":100}},"D5":{"1":{"volume":100}},"E5":{"1":{"volume":100}},"F5":{"1":{"volume":100}},"G5":{"1":{"volume":100}},"H5":{"1":{"volume":100}},"A6":{"1":{"volume":100}},"B6":{"1":{"volume":100}},"C6":{"1":{"volume":100}},"D6":{"1":{"volume":100}},"E6":{"1":{"volume":100}},"F6":{"1":{"volume":100}},"G6":{"1":{"volume":100}},"H6":{"1":{"volume":100}}}},"savedStepForms":{"__INITIAL_DECK_SETUP_STEP__":{"stepType":"manualIntervention","id":"__INITIAL_DECK_SETUP_STEP__","labwareLocationUpdate":{"fixedTrash":"12","a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1":"5","0d460f8a-2163-4eb7-8f48-5c382604971a:opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1":"5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType","01ab8b91-996c-41a2-a11e-57719913979e:opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1":"b5df8f5c-9fc5-4d45-98c2-0ce6bd218fda:temperatureModuleType","32e39cda-1d1d-4e0d-b933-b94cf464e29a:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1":"8d4683d0-7a88-4b33-9363-bd3894a71f9a:magneticModuleType","111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1":"a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType","bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1":"6"},"pipetteLocationUpdate":{"9467efbc-2ad4-40eb-bc05-91c78fd48be2":"left","1b766d4d-ba31-42cc-a49a-73e9d8c67aca":"right"},"moduleLocationUpdate":{"5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType":"1","8d4683d0-7a88-4b33-9363-bd3894a71f9a:magneticModuleType":"9","b5df8f5c-9fc5-4d45-98c2-0ce6bd218fda:temperatureModuleType":"3","a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType":"span7_8_10_11"}},"8506adb8-05bc-49cd-a159-f1af3623012f":{"id":"8506adb8-05bc-49cd-a159-f1af3623012f","stepType":"heaterShaker","stepName":"heater-shaker","stepDetails":"","moduleId":"5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType","setHeaterShakerTemperature":null,"targetHeaterShakerTemperature":null,"targetSpeed":null,"setShake":null,"latchOpen":false,"heaterShakerSetTimer":null,"heaterShakerTimerMinutes":null,"heaterShakerTimerSeconds":null},"28f5eb49-8cac-4658-aa04-2021277f6026":{"id":"28f5eb49-8cac-4658-aa04-2021277f6026","stepType":"thermocycler","stepName":"thermocycler","stepDetails":"","thermocyclerFormType":"thermocyclerState","moduleId":"a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType","blockIsActive":false,"blockTargetTemp":null,"lidIsActive":false,"lidTargetTemp":null,"lidOpen":true,"profileVolume":null,"profileTargetLidTemp":null,"orderedProfileItems":[],"profileItemsById":{},"blockIsActiveHold":false,"blockTargetTempHold":null,"lidIsActiveHold":false,"lidTargetTempHold":null,"lidOpenHold":null},"5fe8dbb8-ccae-4ca8-8015-7d53fd182cb0":{"id":"5fe8dbb8-ccae-4ca8-8015-7d53fd182cb0","stepType":"moveLiquid","stepName":"transfer","stepDetails":"","pipette":"9467efbc-2ad4-40eb-bc05-91c78fd48be2","volume":"20","changeTip":"once","path":"single","aspirate_wells_grouped":false,"aspirate_flowRate":null,"aspirate_labware":"bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1","aspirate_wells":["A1"],"aspirate_wellOrder_first":"t2b","aspirate_wellOrder_second":"l2r","aspirate_mix_checkbox":false,"aspirate_mix_times":null,"aspirate_mix_volume":null,"aspirate_mmFromBottom":null,"aspirate_touchTip_checkbox":false,"aspirate_touchTip_mmFromBottom":null,"dispense_flowRate":null,"dispense_labware":"0d460f8a-2163-4eb7-8f48-5c382604971a:opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1","dispense_wells":["A4"],"dispense_wellOrder_first":"t2b","dispense_wellOrder_second":"l2r","dispense_mix_checkbox":false,"dispense_mix_times":null,"dispense_mix_volume":null,"dispense_mmFromBottom":null,"dispense_touchTip_checkbox":false,"dispense_touchTip_mmFromBottom":null,"disposalVolume_checkbox":true,"disposalVolume_volume":"20","blowout_checkbox":false,"blowout_location":"fixedTrash","preWetTip":false,"aspirate_airGap_checkbox":false,"aspirate_airGap_volume":"20","aspirate_delay_checkbox":false,"aspirate_delay_mmFromBottom":null,"aspirate_delay_seconds":"1","dispense_airGap_checkbox":false,"dispense_airGap_volume":"20","dispense_delay_checkbox":false,"dispense_delay_seconds":"1","dispense_delay_mmFromBottom":null},"ba4d8515-524b-41cd-9953-72fe308e69f0":{"id":"ba4d8515-524b-41cd-9953-72fe308e69f0","stepType":"moveLiquid","stepName":"transfer","stepDetails":"","pipette":"9467efbc-2ad4-40eb-bc05-91c78fd48be2","volume":"20","changeTip":"always","path":"single","aspirate_wells_grouped":false,"aspirate_flowRate":null,"aspirate_labware":"bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1","aspirate_wells":["A1"],"aspirate_wellOrder_first":"t2b","aspirate_wellOrder_second":"l2r","aspirate_mix_checkbox":false,"aspirate_mix_times":null,"aspirate_mix_volume":null,"aspirate_mmFromBottom":null,"aspirate_touchTip_checkbox":false,"aspirate_touchTip_mmFromBottom":null,"dispense_flowRate":null,"dispense_labware":"32e39cda-1d1d-4e0d-b933-b94cf464e29a:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1","dispense_wells":["A7"],"dispense_wellOrder_first":"t2b","dispense_wellOrder_second":"l2r","dispense_mix_checkbox":false,"dispense_mix_times":null,"dispense_mix_volume":null,"dispense_mmFromBottom":null,"dispense_touchTip_checkbox":false,"dispense_touchTip_mmFromBottom":null,"disposalVolume_checkbox":true,"disposalVolume_volume":"20","blowout_checkbox":false,"blowout_location":"fixedTrash","preWetTip":false,"aspirate_airGap_checkbox":false,"aspirate_airGap_volume":"20","aspirate_delay_checkbox":false,"aspirate_delay_mmFromBottom":null,"aspirate_delay_seconds":"1","dispense_airGap_checkbox":false,"dispense_airGap_volume":"20","dispense_delay_checkbox":false,"dispense_delay_seconds":"1","dispense_delay_mmFromBottom":null},"6dff24c4-13ad-4a0e-9eb8-66048f96ca0c":{"id":"6dff24c4-13ad-4a0e-9eb8-66048f96ca0c","stepType":"moveLiquid","stepName":"transfer","stepDetails":"","pipette":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","volume":"25","changeTip":"always","path":"single","aspirate_wells_grouped":false,"aspirate_flowRate":null,"aspirate_labware":"bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1","aspirate_wells":["A1"],"aspirate_wellOrder_first":"t2b","aspirate_wellOrder_second":"l2r","aspirate_mix_checkbox":false,"aspirate_mix_times":null,"aspirate_mix_volume":null,"aspirate_mmFromBottom":null,"aspirate_touchTip_checkbox":false,"aspirate_touchTip_mmFromBottom":null,"dispense_flowRate":null,"dispense_labware":"01ab8b91-996c-41a2-a11e-57719913979e:opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1","dispense_wells":["A3","B3","C3","D3"],"dispense_wellOrder_first":"t2b","dispense_wellOrder_second":"l2r","dispense_mix_checkbox":false,"dispense_mix_times":null,"dispense_mix_volume":null,"dispense_mmFromBottom":null,"dispense_touchTip_checkbox":false,"dispense_touchTip_mmFromBottom":null,"disposalVolume_checkbox":true,"disposalVolume_volume":"20","blowout_checkbox":false,"blowout_location":"fixedTrash","preWetTip":false,"aspirate_airGap_checkbox":false,"aspirate_airGap_volume":"20","aspirate_delay_checkbox":false,"aspirate_delay_mmFromBottom":null,"aspirate_delay_seconds":"1","dispense_airGap_checkbox":false,"dispense_airGap_volume":"20","dispense_delay_checkbox":false,"dispense_delay_seconds":"1","dispense_delay_mmFromBottom":null},"1e9d8a92-e791-452b-9275-638ae8206dda":{"id":"1e9d8a92-e791-452b-9275-638ae8206dda","stepType":"moveLiquid","stepName":"transfer","stepDetails":"","pipette":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","volume":"22","changeTip":"always","path":"single","aspirate_wells_grouped":false,"aspirate_flowRate":null,"aspirate_labware":"bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1","aspirate_wells":["A1"],"aspirate_wellOrder_first":"t2b","aspirate_wellOrder_second":"l2r","aspirate_mix_checkbox":false,"aspirate_mix_times":null,"aspirate_mix_volume":null,"aspirate_mmFromBottom":null,"aspirate_touchTip_checkbox":false,"aspirate_touchTip_mmFromBottom":null,"dispense_flowRate":null,"dispense_labware":"111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1","dispense_wells":["A7","B7","C7","A8","B8","C8"],"dispense_wellOrder_first":"t2b","dispense_wellOrder_second":"l2r","dispense_mix_checkbox":false,"dispense_mix_times":null,"dispense_mix_volume":null,"dispense_mmFromBottom":null,"dispense_touchTip_checkbox":false,"dispense_touchTip_mmFromBottom":null,"disposalVolume_checkbox":true,"disposalVolume_volume":"20","blowout_checkbox":false,"blowout_location":"fixedTrash","preWetTip":false,"aspirate_airGap_checkbox":false,"aspirate_airGap_volume":"20","aspirate_delay_checkbox":false,"aspirate_delay_mmFromBottom":null,"aspirate_delay_seconds":"1","dispense_airGap_checkbox":false,"dispense_airGap_volume":"20","dispense_delay_checkbox":false,"dispense_delay_seconds":"1","dispense_delay_mmFromBottom":null},"ea9a9a34-6d2d-46f1-b10b-fb5d8d28d827":{"id":"ea9a9a34-6d2d-46f1-b10b-fb5d8d28d827","stepType":"thermocycler","stepName":"thermocycler","stepDetails":"","thermocyclerFormType":"thermocyclerState","moduleId":"a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType","blockIsActive":true,"blockTargetTemp":"55","lidIsActive":true,"lidTargetTemp":"50","lidOpen":false,"profileVolume":null,"profileTargetLidTemp":null,"orderedProfileItems":[],"profileItemsById":{},"blockIsActiveHold":false,"blockTargetTempHold":null,"lidIsActiveHold":false,"lidTargetTempHold":null,"lidOpenHold":null},"b07b84ec-f362-440c-b2d8-3949d7169107":{"id":"b07b84ec-f362-440c-b2d8-3949d7169107","stepType":"heaterShaker","stepName":"heater-shaker","stepDetails":"","moduleId":"5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType","setHeaterShakerTemperature":true,"targetHeaterShakerTemperature":"55","targetSpeed":"1000","setShake":true,"latchOpen":false,"heaterShakerSetTimer":null,"heaterShakerTimerMinutes":null,"heaterShakerTimerSeconds":null},"6231a6a8-e287-4e7b-8536-6aa836e29a59":{"id":"6231a6a8-e287-4e7b-8536-6aa836e29a59","stepType":"pause","stepName":"pause","stepDetails":"","pauseAction":"untilTemperature","pauseHour":null,"pauseMinute":null,"pauseSecond":null,"pauseMessage":"","moduleId":"5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType","pauseTemperature":"55"},"bbc840b2-b509-42d9-81dc-428d5c91a978":{"id":"bbc840b2-b509-42d9-81dc-428d5c91a978","stepType":"magnet","stepName":"magnet","stepDetails":"","moduleId":"8d4683d0-7a88-4b33-9363-bd3894a71f9a:magneticModuleType","magnetAction":"engage","engageHeight":"12"},"0431038f-34af-412a-88a6-24a06ce8039f":{"id":"0431038f-34af-412a-88a6-24a06ce8039f","stepType":"temperature","stepName":"temperature","stepDetails":"","moduleId":"b5df8f5c-9fc5-4d45-98c2-0ce6bd218fda:temperatureModuleType","setTemperature":"true","targetTemperature":"80"},"230bc077-a866-45f1-a24b-66238c8ce670":{"id":"230bc077-a866-45f1-a24b-66238c8ce670","stepType":"pause","stepName":"pause","stepDetails":"","pauseAction":"untilTemperature","pauseHour":null,"pauseMinute":null,"pauseSecond":null,"pauseMessage":"","moduleId":"5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType","pauseTemperature":"80"},"3ef16f4c-15ae-407f-9284-0730fd8160b5":{"id":"3ef16f4c-15ae-407f-9284-0730fd8160b5","stepType":"heaterShaker","stepName":"heater-shaker","stepDetails":"","moduleId":"5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType","setHeaterShakerTemperature":null,"targetHeaterShakerTemperature":null,"targetSpeed":null,"setShake":null,"latchOpen":true,"heaterShakerSetTimer":null,"heaterShakerTimerMinutes":null,"heaterShakerTimerSeconds":null},"f83d54c3-76cf-4be3-ba10-fc551d9ec065":{"id":"f83d54c3-76cf-4be3-ba10-fc551d9ec065","stepType":"thermocycler","stepName":"thermocycler","stepDetails":"","thermocyclerFormType":"thermocyclerState","moduleId":"a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType","blockIsActive":false,"blockTargetTemp":null,"lidIsActive":false,"lidTargetTemp":null,"lidOpen":true,"profileVolume":null,"profileTargetLidTemp":null,"orderedProfileItems":[],"profileItemsById":{},"blockIsActiveHold":false,"blockTargetTempHold":null,"lidIsActiveHold":false,"lidTargetTempHold":null,"lidOpenHold":null}},"orderedStepIds":["8506adb8-05bc-49cd-a159-f1af3623012f","28f5eb49-8cac-4658-aa04-2021277f6026","5fe8dbb8-ccae-4ca8-8015-7d53fd182cb0","ba4d8515-524b-41cd-9953-72fe308e69f0","6dff24c4-13ad-4a0e-9eb8-66048f96ca0c","1e9d8a92-e791-452b-9275-638ae8206dda","ea9a9a34-6d2d-46f1-b10b-fb5d8d28d827","b07b84ec-f362-440c-b2d8-3949d7169107","6231a6a8-e287-4e7b-8536-6aa836e29a59","bbc840b2-b509-42d9-81dc-428d5c91a978","0431038f-34af-412a-88a6-24a06ce8039f","230bc077-a866-45f1-a24b-66238c8ce670","3ef16f4c-15ae-407f-9284-0730fd8160b5","f83d54c3-76cf-4be3-ba10-fc551d9ec065"]}},"robot":{"model":"OT-2 Standard","deckId":"ot2_standard"},"pipettes":{"9467efbc-2ad4-40eb-bc05-91c78fd48be2":{"name":"p300_multi_gen2"},"1b766d4d-ba31-42cc-a49a-73e9d8c67aca":{"name":"p300_single_gen2"}},"labware":{"fixedTrash":{"displayName":"Trash","definitionId":"opentrons/opentrons_1_trash_1100ml_fixed/1"},"a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1":{"displayName":"Opentrons 96 Tip Rack 300 µL","definitionId":"opentrons/opentrons_96_tiprack_300ul/1"},"0d460f8a-2163-4eb7-8f48-5c382604971a:opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1":{"displayName":"H/S","definitionId":"opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1"},"01ab8b91-996c-41a2-a11e-57719913979e:opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1":{"displayName":"Temp","definitionId":"opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1"},"32e39cda-1d1d-4e0d-b933-b94cf464e29a:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1":{"displayName":"Mag","definitionId":"opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1"},"111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1":{"displayName":"Themo","definitionId":"opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1"},"bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1":{"displayName":"L1","definitionId":"opentrons/agilent_1_reservoir_290ml/1"}},"liquids":{"0":{"displayName":"L1","description":"","displayColor":"#b925ff"},"1":{"displayName":"L2","description":"","displayColor":"#ffd600"}},"labwareDefinitions":{"opentrons/opentrons_96_tiprack_300ul/1":{"ordering":[["A1","B1","C1","D1","E1","F1","G1","H1"],["A2","B2","C2","D2","E2","F2","G2","H2"],["A3","B3","C3","D3","E3","F3","G3","H3"],["A4","B4","C4","D4","E4","F4","G4","H4"],["A5","B5","C5","D5","E5","F5","G5","H5"],["A6","B6","C6","D6","E6","F6","G6","H6"],["A7","B7","C7","D7","E7","F7","G7","H7"],["A8","B8","C8","D8","E8","F8","G8","H8"],["A9","B9","C9","D9","E9","F9","G9","H9"],["A10","B10","C10","D10","E10","F10","G10","H10"],["A11","B11","C11","D11","E11","F11","G11","H11"],["A12","B12","C12","D12","E12","F12","G12","H12"]],"brand":{"brand":"Opentrons","brandId":[],"links":["https://shop.opentrons.com/collections/opentrons-tips/products/opentrons-300ul-tips"]},"metadata":{"displayName":"Opentrons 96 Tip Rack 300 µL","displayCategory":"tipRack","displayVolumeUnits":"µL","tags":[]},"dimensions":{"xDimension":127.76,"yDimension":85.48,"zDimension":64.49},"wells":{"A1":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":14.38,"y":74.24,"z":5.39},"B1":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":14.38,"y":65.24,"z":5.39},"C1":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":14.38,"y":56.24,"z":5.39},"D1":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":14.38,"y":47.24,"z":5.39},"E1":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":14.38,"y":38.24,"z":5.39},"F1":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":14.38,"y":29.24,"z":5.39},"G1":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":14.38,"y":20.24,"z":5.39},"H1":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":14.38,"y":11.24,"z":5.39},"A2":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":23.38,"y":74.24,"z":5.39},"B2":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":23.38,"y":65.24,"z":5.39},"C2":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":23.38,"y":56.24,"z":5.39},"D2":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":23.38,"y":47.24,"z":5.39},"E2":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":23.38,"y":38.24,"z":5.39},"F2":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":23.38,"y":29.24,"z":5.39},"G2":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":23.38,"y":20.24,"z":5.39},"H2":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":23.38,"y":11.24,"z":5.39},"A3":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":32.38,"y":74.24,"z":5.39},"B3":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":32.38,"y":65.24,"z":5.39},"C3":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":32.38,"y":56.24,"z":5.39},"D3":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":32.38,"y":47.24,"z":5.39},"E3":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":32.38,"y":38.24,"z":5.39},"F3":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":32.38,"y":29.24,"z":5.39},"G3":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":32.38,"y":20.24,"z":5.39},"H3":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":32.38,"y":11.24,"z":5.39},"A4":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":41.38,"y":74.24,"z":5.39},"B4":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":41.38,"y":65.24,"z":5.39},"C4":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":41.38,"y":56.24,"z":5.39},"D4":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":41.38,"y":47.24,"z":5.39},"E4":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":41.38,"y":38.24,"z":5.39},"F4":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":41.38,"y":29.24,"z":5.39},"G4":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":41.38,"y":20.24,"z":5.39},"H4":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":41.38,"y":11.24,"z":5.39},"A5":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":50.38,"y":74.24,"z":5.39},"B5":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":50.38,"y":65.24,"z":5.39},"C5":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":50.38,"y":56.24,"z":5.39},"D5":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":50.38,"y":47.24,"z":5.39},"E5":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":50.38,"y":38.24,"z":5.39},"F5":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":50.38,"y":29.24,"z":5.39},"G5":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":50.38,"y":20.24,"z":5.39},"H5":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":50.38,"y":11.24,"z":5.39},"A6":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":59.38,"y":74.24,"z":5.39},"B6":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":59.38,"y":65.24,"z":5.39},"C6":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":59.38,"y":56.24,"z":5.39},"D6":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":59.38,"y":47.24,"z":5.39},"E6":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":59.38,"y":38.24,"z":5.39},"F6":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":59.38,"y":29.24,"z":5.39},"G6":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":59.38,"y":20.24,"z":5.39},"H6":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":59.38,"y":11.24,"z":5.39},"A7":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":68.38,"y":74.24,"z":5.39},"B7":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":68.38,"y":65.24,"z":5.39},"C7":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":68.38,"y":56.24,"z":5.39},"D7":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":68.38,"y":47.24,"z":5.39},"E7":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":68.38,"y":38.24,"z":5.39},"F7":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":68.38,"y":29.24,"z":5.39},"G7":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":68.38,"y":20.24,"z":5.39},"H7":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":68.38,"y":11.24,"z":5.39},"A8":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":77.38,"y":74.24,"z":5.39},"B8":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":77.38,"y":65.24,"z":5.39},"C8":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":77.38,"y":56.24,"z":5.39},"D8":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":77.38,"y":47.24,"z":5.39},"E8":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":77.38,"y":38.24,"z":5.39},"F8":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":77.38,"y":29.24,"z":5.39},"G8":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":77.38,"y":20.24,"z":5.39},"H8":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":77.38,"y":11.24,"z":5.39},"A9":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":86.38,"y":74.24,"z":5.39},"B9":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":86.38,"y":65.24,"z":5.39},"C9":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":86.38,"y":56.24,"z":5.39},"D9":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":86.38,"y":47.24,"z":5.39},"E9":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":86.38,"y":38.24,"z":5.39},"F9":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":86.38,"y":29.24,"z":5.39},"G9":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":86.38,"y":20.24,"z":5.39},"H9":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":86.38,"y":11.24,"z":5.39},"A10":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":95.38,"y":74.24,"z":5.39},"B10":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":95.38,"y":65.24,"z":5.39},"C10":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":95.38,"y":56.24,"z":5.39},"D10":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":95.38,"y":47.24,"z":5.39},"E10":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":95.38,"y":38.24,"z":5.39},"F10":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":95.38,"y":29.24,"z":5.39},"G10":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":95.38,"y":20.24,"z":5.39},"H10":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":95.38,"y":11.24,"z":5.39},"A11":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":104.38,"y":74.24,"z":5.39},"B11":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":104.38,"y":65.24,"z":5.39},"C11":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":104.38,"y":56.24,"z":5.39},"D11":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":104.38,"y":47.24,"z":5.39},"E11":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":104.38,"y":38.24,"z":5.39},"F11":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":104.38,"y":29.24,"z":5.39},"G11":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":104.38,"y":20.24,"z":5.39},"H11":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":104.38,"y":11.24,"z":5.39},"A12":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":113.38,"y":74.24,"z":5.39},"B12":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":113.38,"y":65.24,"z":5.39},"C12":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":113.38,"y":56.24,"z":5.39},"D12":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":113.38,"y":47.24,"z":5.39},"E12":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":113.38,"y":38.24,"z":5.39},"F12":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":113.38,"y":29.24,"z":5.39},"G12":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":113.38,"y":20.24,"z":5.39},"H12":{"depth":59.3,"shape":"circular","diameter":5.23,"totalLiquidVolume":300,"x":113.38,"y":11.24,"z":5.39}},"groups":[{"metadata":{},"wells":["A1","B1","C1","D1","E1","F1","G1","H1","A2","B2","C2","D2","E2","F2","G2","H2","A3","B3","C3","D3","E3","F3","G3","H3","A4","B4","C4","D4","E4","F4","G4","H4","A5","B5","C5","D5","E5","F5","G5","H5","A6","B6","C6","D6","E6","F6","G6","H6","A7","B7","C7","D7","E7","F7","G7","H7","A8","B8","C8","D8","E8","F8","G8","H8","A9","B9","C9","D9","E9","F9","G9","H9","A10","B10","C10","D10","E10","F10","G10","H10","A11","B11","C11","D11","E11","F11","G11","H11","A12","B12","C12","D12","E12","F12","G12","H12"]}],"parameters":{"format":"96Standard","isTiprack":true,"tipLength":59.3,"tipOverlap":7.47,"isMagneticModuleCompatible":false,"loadName":"opentrons_96_tiprack_300ul"},"namespace":"opentrons","version":1,"schemaVersion":2,"cornerOffsetFromSlot":{"x":0,"y":0,"z":0}},"opentrons/opentrons_1_trash_1100ml_fixed/1":{"ordering":[["A1"]],"metadata":{"displayCategory":"trash","displayVolumeUnits":"mL","displayName":"Opentrons Fixed Trash","tags":[]},"schemaVersion":2,"version":1,"namespace":"opentrons","dimensions":{"xDimension":172.86,"yDimension":165.86,"zDimension":82},"parameters":{"format":"trash","isTiprack":false,"loadName":"opentrons_1_trash_1100ml_fixed","isMagneticModuleCompatible":false,"quirks":["fixedTrash","centerMultichannelOnWells","touchTipDisabled"]},"wells":{"A1":{"shape":"rectangular","yDimension":165.67,"xDimension":107.11,"totalLiquidVolume":1100000,"depth":0,"x":82.84,"y":80,"z":82}},"brand":{"brand":"Opentrons"},"groups":[{"wells":["A1"],"metadata":{}}],"cornerOffsetFromSlot":{"x":0,"y":0,"z":0}},"opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1":{"ordering":[["A1","B1","C1","D1","E1","F1","G1","H1"],["A2","B2","C2","D2","E2","F2","G2","H2"],["A3","B3","C3","D3","E3","F3","G3","H3"],["A4","B4","C4","D4","E4","F4","G4","H4"],["A5","B5","C5","D5","E5","F5","G5","H5"],["A6","B6","C6","D6","E6","F6","G6","H6"],["A7","B7","C7","D7","E7","F7","G7","H7"],["A8","B8","C8","D8","E8","F8","G8","H8"],["A9","B9","C9","D9","E9","F9","G9","H9"],["A10","B10","C10","D10","E10","F10","G10","H10"],["A11","B11","C11","D11","E11","F11","G11","H11"],["A12","B12","C12","D12","E12","F12","G12","H12"]],"brand":{"brand":"Opentrons","brandId":[],"links":[]},"metadata":{"displayName":"Opentrons 96 Deep Well Adapter with NEST Deep Well Plate 2 mL","displayCategory":"aluminumBlock","displayVolumeUnits":"µL","tags":[]},"dimensions":{"xDimension":127.6,"yDimension":85.3,"zDimension":42.25},"wells":{"A1":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":14.3,"y":74.15,"z":4.25},"B1":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":14.3,"y":65.15,"z":4.25},"C1":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":14.3,"y":56.15,"z":4.25},"D1":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":14.3,"y":47.15,"z":4.25},"E1":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":14.3,"y":38.15,"z":4.25},"F1":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":14.3,"y":29.15,"z":4.25},"G1":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":14.3,"y":20.15,"z":4.25},"H1":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":14.3,"y":11.15,"z":4.25},"A2":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":23.3,"y":74.15,"z":4.25},"B2":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":23.3,"y":65.15,"z":4.25},"C2":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":23.3,"y":56.15,"z":4.25},"D2":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":23.3,"y":47.15,"z":4.25},"E2":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":23.3,"y":38.15,"z":4.25},"F2":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":23.3,"y":29.15,"z":4.25},"G2":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":23.3,"y":20.15,"z":4.25},"H2":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":23.3,"y":11.15,"z":4.25},"A3":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":32.3,"y":74.15,"z":4.25},"B3":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":32.3,"y":65.15,"z":4.25},"C3":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":32.3,"y":56.15,"z":4.25},"D3":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":32.3,"y":47.15,"z":4.25},"E3":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":32.3,"y":38.15,"z":4.25},"F3":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":32.3,"y":29.15,"z":4.25},"G3":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":32.3,"y":20.15,"z":4.25},"H3":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":32.3,"y":11.15,"z":4.25},"A4":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":41.3,"y":74.15,"z":4.25},"B4":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":41.3,"y":65.15,"z":4.25},"C4":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":41.3,"y":56.15,"z":4.25},"D4":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":41.3,"y":47.15,"z":4.25},"E4":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":41.3,"y":38.15,"z":4.25},"F4":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":41.3,"y":29.15,"z":4.25},"G4":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":41.3,"y":20.15,"z":4.25},"H4":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":41.3,"y":11.15,"z":4.25},"A5":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":50.3,"y":74.15,"z":4.25},"B5":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":50.3,"y":65.15,"z":4.25},"C5":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":50.3,"y":56.15,"z":4.25},"D5":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":50.3,"y":47.15,"z":4.25},"E5":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":50.3,"y":38.15,"z":4.25},"F5":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":50.3,"y":29.15,"z":4.25},"G5":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":50.3,"y":20.15,"z":4.25},"H5":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":50.3,"y":11.15,"z":4.25},"A6":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":59.3,"y":74.15,"z":4.25},"B6":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":59.3,"y":65.15,"z":4.25},"C6":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":59.3,"y":56.15,"z":4.25},"D6":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":59.3,"y":47.15,"z":4.25},"E6":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":59.3,"y":38.15,"z":4.25},"F6":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":59.3,"y":29.15,"z":4.25},"G6":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":59.3,"y":20.15,"z":4.25},"H6":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":59.3,"y":11.15,"z":4.25},"A7":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":68.3,"y":74.15,"z":4.25},"B7":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":68.3,"y":65.15,"z":4.25},"C7":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":68.3,"y":56.15,"z":4.25},"D7":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":68.3,"y":47.15,"z":4.25},"E7":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":68.3,"y":38.15,"z":4.25},"F7":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":68.3,"y":29.15,"z":4.25},"G7":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":68.3,"y":20.15,"z":4.25},"H7":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":68.3,"y":11.15,"z":4.25},"A8":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":77.3,"y":74.15,"z":4.25},"B8":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":77.3,"y":65.15,"z":4.25},"C8":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":77.3,"y":56.15,"z":4.25},"D8":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":77.3,"y":47.15,"z":4.25},"E8":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":77.3,"y":38.15,"z":4.25},"F8":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":77.3,"y":29.15,"z":4.25},"G8":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":77.3,"y":20.15,"z":4.25},"H8":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":77.3,"y":11.15,"z":4.25},"A9":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":86.3,"y":74.15,"z":4.25},"B9":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":86.3,"y":65.15,"z":4.25},"C9":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":86.3,"y":56.15,"z":4.25},"D9":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":86.3,"y":47.15,"z":4.25},"E9":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":86.3,"y":38.15,"z":4.25},"F9":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":86.3,"y":29.15,"z":4.25},"G9":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":86.3,"y":20.15,"z":4.25},"H9":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":86.3,"y":11.15,"z":4.25},"A10":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":95.3,"y":74.15,"z":4.25},"B10":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":95.3,"y":65.15,"z":4.25},"C10":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":95.3,"y":56.15,"z":4.25},"D10":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":95.3,"y":47.15,"z":4.25},"E10":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":95.3,"y":38.15,"z":4.25},"F10":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":95.3,"y":29.15,"z":4.25},"G10":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":95.3,"y":20.15,"z":4.25},"H10":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":95.3,"y":11.15,"z":4.25},"A11":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":104.3,"y":74.15,"z":4.25},"B11":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":104.3,"y":65.15,"z":4.25},"C11":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":104.3,"y":56.15,"z":4.25},"D11":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":104.3,"y":47.15,"z":4.25},"E11":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":104.3,"y":38.15,"z":4.25},"F11":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":104.3,"y":29.15,"z":4.25},"G11":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":104.3,"y":20.15,"z":4.25},"H11":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":104.3,"y":11.15,"z":4.25},"A12":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":113.3,"y":74.15,"z":4.25},"B12":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":113.3,"y":65.15,"z":4.25},"C12":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":113.3,"y":56.15,"z":4.25},"D12":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":113.3,"y":47.15,"z":4.25},"E12":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":113.3,"y":38.15,"z":4.25},"F12":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":113.3,"y":29.15,"z":4.25},"G12":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":113.3,"y":20.15,"z":4.25},"H12":{"depth":38,"totalLiquidVolume":2000,"shape":"rectangular","xDimension":8.2,"yDimension":8.2,"x":113.3,"y":11.15,"z":4.25}},"groups":[{"metadata":{"displayName":"NEST 96 Deepwell Plate 2mL","displayCategory":"wellPlate","wellBottomShape":"v"},"brand":{"brand":"NEST","brandId":["503501","503001"],"links":["https://www.nest-biotech.com/deep-well-plates/59253726.html"]},"wells":["A1","B1","C1","D1","E1","F1","G1","H1","A2","B2","C2","D2","E2","F2","G2","H2","A3","B3","C3","D3","E3","F3","G3","H3","A4","B4","C4","D4","E4","F4","G4","H4","A5","B5","C5","D5","E5","F5","G5","H5","A6","B6","C6","D6","E6","F6","G6","H6","A7","B7","C7","D7","E7","F7","G7","H7","A8","B8","C8","D8","E8","F8","G8","H8","A9","B9","C9","D9","E9","F9","G9","H9","A10","B10","C10","D10","E10","F10","G10","H10","A11","B11","C11","D11","E11","F11","G11","H11","A12","B12","C12","D12","E12","F12","G12","H12"]}],"parameters":{"format":"96Standard","quirks":[],"isTiprack":false,"isMagneticModuleCompatible":false,"loadName":"opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep"},"namespace":"opentrons","version":1,"schemaVersion":2,"cornerOffsetFromSlot":{"x":0,"y":0,"z":0}},"opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1":{"ordering":[["A1","B1","C1","D1"],["A2","B2","C2","D2"],["A3","B3","C3","D3"],["A4","B4","C4","D4"],["A5","B5","C5","D5"],["A6","B6","C6","D6"]],"schemaVersion":2,"version":1,"namespace":"opentrons","metadata":{"displayName":"Opentrons 24 Well Aluminum Block with Generic 2 mL Screwcap","displayVolumeUnits":"mL","displayCategory":"aluminumBlock","tags":[]},"dimensions":{"xDimension":127.75,"yDimension":85.5,"zDimension":42},"parameters":{"format":"irregular","isTiprack":false,"isMagneticModuleCompatible":false,"loadName":"opentrons_24_aluminumblock_generic_2ml_screwcap"},"wells":{"D1":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":20.75,"y":16.88,"z":6.7},"C1":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":20.75,"y":34.13,"z":6.7},"B1":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":20.75,"y":51.38,"z":6.7},"A1":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":20.75,"y":68.63,"z":6.7},"D2":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":38,"y":16.88,"z":6.7},"C2":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":38,"y":34.13,"z":6.7},"B2":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":38,"y":51.38,"z":6.7},"A2":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":38,"y":68.63,"z":6.7},"D3":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":55.25,"y":16.88,"z":6.7},"C3":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":55.25,"y":34.13,"z":6.7},"B3":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":55.25,"y":51.38,"z":6.7},"A3":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":55.25,"y":68.63,"z":6.7},"D4":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":72.5,"y":16.88,"z":6.7},"C4":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":72.5,"y":34.13,"z":6.7},"B4":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":72.5,"y":51.38,"z":6.7},"A4":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":72.5,"y":68.63,"z":6.7},"D5":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":89.75,"y":16.88,"z":6.7},"C5":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":89.75,"y":34.13,"z":6.7},"B5":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":89.75,"y":51.38,"z":6.7},"A5":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":89.75,"y":68.63,"z":6.7},"D6":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":107,"y":16.88,"z":6.7},"C6":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":107,"y":34.13,"z":6.7},"B6":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":107,"y":51.38,"z":6.7},"A6":{"shape":"circular","depth":42,"diameter":8.5,"totalLiquidVolume":2000,"x":107,"y":68.63,"z":6.7}},"brand":{"brand":"Opentrons","brandId":[],"links":["https://shop.opentrons.com/collections/hardware-modules/products/aluminum-block-set"]},"groups":[{"wells":["A1","B1","C1","D1","A2","B2","C2","D2","A3","B3","C3","D3","A4","B4","C4","D4","A5","B5","C5","D5","A6","B6","C6","D6"],"metadata":{"displayName":"Generic 2 mL Screwcap","displayCategory":"tubeRack","wellBottomShape":"v"},"brand":{"brand":"generic","brandId":[],"links":[]}}],"cornerOffsetFromSlot":{"x":0,"y":0,"z":0}},"opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1":{"ordering":[["A1","B1","C1","D1","E1","F1","G1","H1"],["A2","B2","C2","D2","E2","F2","G2","H2"],["A3","B3","C3","D3","E3","F3","G3","H3"],["A4","B4","C4","D4","E4","F4","G4","H4"],["A5","B5","C5","D5","E5","F5","G5","H5"],["A6","B6","C6","D6","E6","F6","G6","H6"],["A7","B7","C7","D7","E7","F7","G7","H7"],["A8","B8","C8","D8","E8","F8","G8","H8"],["A9","B9","C9","D9","E9","F9","G9","H9"],["A10","B10","C10","D10","E10","F10","G10","H10"],["A11","B11","C11","D11","E11","F11","G11","H11"],["A12","B12","C12","D12","E12","F12","G12","H12"]],"brand":{"brand":"NEST","brandId":["402501"],"links":["https://www.nest-biotech.com/pcr-plates/58773587.html"]},"metadata":{"displayName":"NEST 96 Well Plate 100 µL PCR Full Skirt","displayCategory":"wellPlate","displayVolumeUnits":"µL","tags":[]},"dimensions":{"xDimension":127.76,"yDimension":85.48,"zDimension":15.7},"wells":{"A1":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":14.38,"y":74.24,"z":0.92},"B1":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":14.38,"y":65.24,"z":0.92},"C1":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":14.38,"y":56.24,"z":0.92},"D1":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":14.38,"y":47.24,"z":0.92},"E1":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":14.38,"y":38.24,"z":0.92},"F1":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":14.38,"y":29.24,"z":0.92},"G1":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":14.38,"y":20.24,"z":0.92},"H1":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":14.38,"y":11.24,"z":0.92},"A2":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":23.38,"y":74.24,"z":0.92},"B2":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":23.38,"y":65.24,"z":0.92},"C2":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":23.38,"y":56.24,"z":0.92},"D2":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":23.38,"y":47.24,"z":0.92},"E2":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":23.38,"y":38.24,"z":0.92},"F2":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":23.38,"y":29.24,"z":0.92},"G2":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":23.38,"y":20.24,"z":0.92},"H2":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":23.38,"y":11.24,"z":0.92},"A3":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":32.38,"y":74.24,"z":0.92},"B3":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":32.38,"y":65.24,"z":0.92},"C3":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":32.38,"y":56.24,"z":0.92},"D3":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":32.38,"y":47.24,"z":0.92},"E3":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":32.38,"y":38.24,"z":0.92},"F3":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":32.38,"y":29.24,"z":0.92},"G3":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":32.38,"y":20.24,"z":0.92},"H3":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":32.38,"y":11.24,"z":0.92},"A4":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":41.38,"y":74.24,"z":0.92},"B4":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":41.38,"y":65.24,"z":0.92},"C4":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":41.38,"y":56.24,"z":0.92},"D4":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":41.38,"y":47.24,"z":0.92},"E4":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":41.38,"y":38.24,"z":0.92},"F4":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":41.38,"y":29.24,"z":0.92},"G4":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":41.38,"y":20.24,"z":0.92},"H4":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":41.38,"y":11.24,"z":0.92},"A5":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":50.38,"y":74.24,"z":0.92},"B5":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":50.38,"y":65.24,"z":0.92},"C5":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":50.38,"y":56.24,"z":0.92},"D5":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":50.38,"y":47.24,"z":0.92},"E5":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":50.38,"y":38.24,"z":0.92},"F5":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":50.38,"y":29.24,"z":0.92},"G5":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":50.38,"y":20.24,"z":0.92},"H5":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":50.38,"y":11.24,"z":0.92},"A6":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":59.38,"y":74.24,"z":0.92},"B6":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":59.38,"y":65.24,"z":0.92},"C6":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":59.38,"y":56.24,"z":0.92},"D6":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":59.38,"y":47.24,"z":0.92},"E6":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":59.38,"y":38.24,"z":0.92},"F6":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":59.38,"y":29.24,"z":0.92},"G6":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":59.38,"y":20.24,"z":0.92},"H6":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":59.38,"y":11.24,"z":0.92},"A7":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":68.38,"y":74.24,"z":0.92},"B7":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":68.38,"y":65.24,"z":0.92},"C7":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":68.38,"y":56.24,"z":0.92},"D7":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":68.38,"y":47.24,"z":0.92},"E7":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":68.38,"y":38.24,"z":0.92},"F7":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":68.38,"y":29.24,"z":0.92},"G7":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":68.38,"y":20.24,"z":0.92},"H7":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":68.38,"y":11.24,"z":0.92},"A8":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":77.38,"y":74.24,"z":0.92},"B8":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":77.38,"y":65.24,"z":0.92},"C8":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":77.38,"y":56.24,"z":0.92},"D8":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":77.38,"y":47.24,"z":0.92},"E8":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":77.38,"y":38.24,"z":0.92},"F8":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":77.38,"y":29.24,"z":0.92},"G8":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":77.38,"y":20.24,"z":0.92},"H8":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":77.38,"y":11.24,"z":0.92},"A9":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":86.38,"y":74.24,"z":0.92},"B9":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":86.38,"y":65.24,"z":0.92},"C9":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":86.38,"y":56.24,"z":0.92},"D9":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":86.38,"y":47.24,"z":0.92},"E9":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":86.38,"y":38.24,"z":0.92},"F9":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":86.38,"y":29.24,"z":0.92},"G9":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":86.38,"y":20.24,"z":0.92},"H9":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":86.38,"y":11.24,"z":0.92},"A10":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":95.38,"y":74.24,"z":0.92},"B10":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":95.38,"y":65.24,"z":0.92},"C10":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":95.38,"y":56.24,"z":0.92},"D10":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":95.38,"y":47.24,"z":0.92},"E10":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":95.38,"y":38.24,"z":0.92},"F10":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":95.38,"y":29.24,"z":0.92},"G10":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":95.38,"y":20.24,"z":0.92},"H10":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":95.38,"y":11.24,"z":0.92},"A11":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":104.38,"y":74.24,"z":0.92},"B11":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":104.38,"y":65.24,"z":0.92},"C11":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":104.38,"y":56.24,"z":0.92},"D11":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":104.38,"y":47.24,"z":0.92},"E11":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":104.38,"y":38.24,"z":0.92},"F11":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":104.38,"y":29.24,"z":0.92},"G11":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":104.38,"y":20.24,"z":0.92},"H11":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":104.38,"y":11.24,"z":0.92},"A12":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":113.38,"y":74.24,"z":0.92},"B12":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":113.38,"y":65.24,"z":0.92},"C12":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":113.38,"y":56.24,"z":0.92},"D12":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":113.38,"y":47.24,"z":0.92},"E12":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":113.38,"y":38.24,"z":0.92},"F12":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":113.38,"y":29.24,"z":0.92},"G12":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":113.38,"y":20.24,"z":0.92},"H12":{"depth":14.78,"shape":"circular","diameter":5.34,"totalLiquidVolume":100,"x":113.38,"y":11.24,"z":0.92}},"groups":[{"metadata":{"wellBottomShape":"v"},"wells":["A1","B1","C1","D1","E1","F1","G1","H1","A2","B2","C2","D2","E2","F2","G2","H2","A3","B3","C3","D3","E3","F3","G3","H3","A4","B4","C4","D4","E4","F4","G4","H4","A5","B5","C5","D5","E5","F5","G5","H5","A6","B6","C6","D6","E6","F6","G6","H6","A7","B7","C7","D7","E7","F7","G7","H7","A8","B8","C8","D8","E8","F8","G8","H8","A9","B9","C9","D9","E9","F9","G9","H9","A10","B10","C10","D10","E10","F10","G10","H10","A11","B11","C11","D11","E11","F11","G11","H11","A12","B12","C12","D12","E12","F12","G12","H12"]}],"parameters":{"format":"96Standard","isTiprack":false,"isMagneticModuleCompatible":true,"magneticModuleEngageHeight":20,"loadName":"nest_96_wellplate_100ul_pcr_full_skirt"},"namespace":"opentrons","version":1,"schemaVersion":2,"cornerOffsetFromSlot":{"x":0,"y":0,"z":0}},"opentrons/agilent_1_reservoir_290ml/1":{"ordering":[["A1"]],"brand":{"brand":"Agilent","brandId":["201252-100"],"links":["https://www.agilent.com/store/en_US/Prod-201252-100/201252-100"]},"metadata":{"displayName":"Agilent 1 Well Reservoir 290 mL","displayCategory":"reservoir","displayVolumeUnits":"mL","tags":[]},"dimensions":{"xDimension":127.76,"yDimension":85.57,"zDimension":44.04},"wells":{"A1":{"depth":39.22,"shape":"rectangular","xDimension":108,"yDimension":72,"totalLiquidVolume":290000,"x":63.88,"y":42.785,"z":4.82}},"groups":[{"wells":["A1"],"metadata":{"wellBottomShape":"v"}}],"parameters":{"format":"trough","isTiprack":false,"isMagneticModuleCompatible":false,"loadName":"agilent_1_reservoir_290ml","quirks":["centerMultichannelOnWells","touchTipDisabled"]},"namespace":"opentrons","version":1,"schemaVersion":2,"cornerOffsetFromSlot":{"x":0,"y":0,"z":0}}},"$otSharedSchema":"#/protocol/schemas/6","schemaVersion":6,"modules":{"5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType":{"model":"heaterShakerModuleV1"},"8d4683d0-7a88-4b33-9363-bd3894a71f9a:magneticModuleType":{"model":"magneticModuleV1"},"b5df8f5c-9fc5-4d45-98c2-0ce6bd218fda:temperatureModuleType":{"model":"temperatureModuleV1"},"a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType":{"model":"thermocyclerModuleV1"}},"commands":[{"key":"9fb4e8f4-186e-4063-aafe-847b7f5f5cad","commandType":"loadPipette","params":{"pipetteId":"9467efbc-2ad4-40eb-bc05-91c78fd48be2","mount":"left"}},{"key":"789dde75-0ec2-490c-ab51-16f0d162e638","commandType":"loadPipette","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","mount":"right"}},{"key":"42b2a4d7-403c-43bd-bc44-e61930576339","commandType":"loadModule","params":{"moduleId":"5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType","location":{"slotName":"1"}}},{"key":"5518b369-b938-4ac4-b2ba-adde29927e2a","commandType":"loadModule","params":{"moduleId":"8d4683d0-7a88-4b33-9363-bd3894a71f9a:magneticModuleType","location":{"slotName":"9"}}},{"key":"40f6b56d-05f1-46ab-a262-24601afb0f51","commandType":"loadModule","params":{"moduleId":"b5df8f5c-9fc5-4d45-98c2-0ce6bd218fda:temperatureModuleType","location":{"slotName":"3"}}},{"key":"3ae25b1b-2242-423a-8fb4-3f682dececd0","commandType":"loadModule","params":{"moduleId":"a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType","location":{"slotName":"7"}}},{"key":"d458d31a-bf76-40ec-97e5-113e27bea5fd","commandType":"loadLabware","params":{"labwareId":"a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1","location":{"slotName":"5"}}},{"key":"4cc07fbd-92e7-4454-ab09-2d150afbfee6","commandType":"loadLabware","params":{"labwareId":"0d460f8a-2163-4eb7-8f48-5c382604971a:opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1","location":{"moduleId":"5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType"}}},{"key":"7084ef04-3926-4bdb-bfba-0cef939464bd","commandType":"loadLabware","params":{"labwareId":"01ab8b91-996c-41a2-a11e-57719913979e:opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1","location":{"moduleId":"b5df8f5c-9fc5-4d45-98c2-0ce6bd218fda:temperatureModuleType"}}},{"key":"416661fd-3da9-4f83-9401-18454a9a18e2","commandType":"loadLabware","params":{"labwareId":"32e39cda-1d1d-4e0d-b933-b94cf464e29a:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1","location":{"moduleId":"8d4683d0-7a88-4b33-9363-bd3894a71f9a:magneticModuleType"}}},{"key":"f9b8458a-cf8b-47f9-8726-70364a361821","commandType":"loadLabware","params":{"labwareId":"111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1","location":{"moduleId":"a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType"}}},{"key":"e6b14558-83dd-46a0-88a8-7e7dc38a8869","commandType":"loadLabware","params":{"labwareId":"bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1","location":{"slotName":"6"}}},{"commandType":"loadLiquid","key":"2da37722-8a55-4955-aace-409ba03378df","params":{"liquidId":"1","labwareId":"01ab8b91-996c-41a2-a11e-57719913979e:opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1","volumeByWell":{"A1":300,"B1":300,"C1":300,"D1":300,"A2":300,"B2":300,"C2":300,"D2":300}}},{"commandType":"loadLiquid","key":"8c92f196-8a7f-47b2-83d3-1526db9a39db","params":{"liquidId":"1","labwareId":"0d460f8a-2163-4eb7-8f48-5c382604971a:opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1","volumeByWell":{"A1":20,"B1":20,"C1":20,"D1":20,"E1":20,"F1":20,"G1":20,"H1":20,"A2":20,"B2":20,"C2":20,"D2":20,"E2":20,"F2":20,"G2":20,"H2":20,"A3":20,"B3":20,"C3":20,"D3":20,"E3":20,"F3":20,"G3":20,"H3":20}}},{"commandType":"loadLiquid","key":"9d29b8c9-0f68-4d9a-89ac-c3509674d6ab","params":{"liquidId":"1","labwareId":"111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1","volumeByWell":{"A1":100,"B1":100,"C1":100,"D1":100,"E1":100,"F1":100,"G1":100,"H1":100,"A2":100,"B2":100,"C2":100,"D2":100,"E2":100,"F2":100,"G2":100,"H2":100,"A3":100,"B3":100,"C3":100,"D3":100,"E3":100,"F3":100,"G3":100,"H3":100,"A4":100,"B4":100,"C4":100,"D4":100,"E4":100,"F4":100,"G4":100,"H4":100,"A5":100,"B5":100,"C5":100,"D5":100,"E5":100,"F5":100,"G5":100,"H5":100,"A6":100,"B6":100,"C6":100,"D6":100,"E6":100,"F6":100,"G6":100,"H6":100}}},{"commandType":"loadLiquid","key":"d9c86281-67c0-432a-8fb2-3a200f280e5e","params":{"liquidId":"1","labwareId":"32e39cda-1d1d-4e0d-b933-b94cf464e29a:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1","volumeByWell":{"A1":100,"B1":100,"C1":100,"D1":100,"E1":100,"F1":100,"G1":100,"H1":100,"A2":100,"B2":100,"C2":100,"D2":100,"E2":100,"F2":100,"G2":100,"H2":100,"A3":100,"B3":100,"C3":100,"D3":100,"E3":100,"F3":100,"G3":100,"H3":100,"A4":100,"B4":100,"C4":100,"D4":100,"E4":100,"F4":100,"G4":100,"H4":100,"A5":100,"B5":100,"C5":100,"D5":100,"E5":100,"F5":100,"G5":100,"H5":100,"A6":100,"B6":100,"C6":100,"D6":100,"E6":100,"F6":100,"G6":100,"H6":100}}},{"commandType":"loadLiquid","key":"b000cefe-8e3e-45d3-85e3-efe29e8ed4ec","params":{"liquidId":"0","labwareId":"bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1","volumeByWell":{"A1":29000}}},{"commandType":"heaterShaker/closeLabwareLatch","key":"57a860ec-3a3f-4b94-804d-dc4ebc3913cb","params":{"moduleId":"5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType"}},{"commandType":"heaterShaker/deactivateHeater","key":"30cddb2c-0a38-4d81-a8aa-1f355895dbe9","params":{"moduleId":"5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType"}},{"commandType":"heaterShaker/deactivateShaker","key":"ef4ce9a1-61e7-4aed-a4ae-24c066236368","params":{"moduleId":"5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType"}},{"commandType":"thermocycler/openLid","key":"8f2eb96e-eb4c-476e-8bdf-0d27684beb09","params":{"moduleId":"a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType"}},{"commandType":"pickUpTip","key":"9583b372-b0a7-407a-b4a5-e847dd691beb","params":{"pipetteId":"9467efbc-2ad4-40eb-bc05-91c78fd48be2","labwareId":"a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1","wellName":"A1"}},{"commandType":"aspirate","key":"55fc7a88-02c8-45ef-87f6-a44c8f3d11db","params":{"pipetteId":"9467efbc-2ad4-40eb-bc05-91c78fd48be2","volume":20,"labwareId":"bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1","wellName":"A1","wellLocation":{"origin":"bottom","offset":{"z":1}},"flowRate":94}},{"commandType":"dispense","key":"e004e404-9481-4c56-ad5a-96a37a6b81c9","params":{"pipetteId":"9467efbc-2ad4-40eb-bc05-91c78fd48be2","volume":20,"labwareId":"0d460f8a-2163-4eb7-8f48-5c382604971a:opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1","wellName":"A4","wellLocation":{"origin":"bottom","offset":{"z":0.5}},"flowRate":94}},{"commandType":"dropTip","key":"fa620ea5-73c3-419f-8c37-197bbfb45d45","params":{"pipetteId":"9467efbc-2ad4-40eb-bc05-91c78fd48be2","labwareId":"fixedTrash","wellName":"A1"}},{"commandType":"pickUpTip","key":"37f23342-5406-43c4-9d2b-4f8e66a9b372","params":{"pipetteId":"9467efbc-2ad4-40eb-bc05-91c78fd48be2","labwareId":"a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1","wellName":"A2"}},{"commandType":"aspirate","key":"3d949fd7-45f8-4b57-a02d-3e5462d92483","params":{"pipetteId":"9467efbc-2ad4-40eb-bc05-91c78fd48be2","volume":20,"labwareId":"bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1","wellName":"A1","wellLocation":{"origin":"bottom","offset":{"z":1}},"flowRate":94}},{"commandType":"dispense","key":"39106345-35da-49ce-9683-8f0d551cb98f","params":{"pipetteId":"9467efbc-2ad4-40eb-bc05-91c78fd48be2","volume":20,"labwareId":"32e39cda-1d1d-4e0d-b933-b94cf464e29a:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1","wellName":"A7","wellLocation":{"origin":"bottom","offset":{"z":0.5}},"flowRate":94}},{"commandType":"dropTip","key":"9b7b49e5-8923-4e11-bf18-3da29a7ddf77","params":{"pipetteId":"9467efbc-2ad4-40eb-bc05-91c78fd48be2","labwareId":"fixedTrash","wellName":"A1"}},{"commandType":"pickUpTip","key":"0c165af0-08c0-4c5d-937a-4709e02ca85f","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","labwareId":"a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1","wellName":"A3"}},{"commandType":"aspirate","key":"aaeae20e-8acb-4af0-a03e-676ed9451166","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","volume":25,"labwareId":"bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1","wellName":"A1","wellLocation":{"origin":"bottom","offset":{"z":1}},"flowRate":46.43}},{"commandType":"dispense","key":"a36a645b-9d7f-41c3-b04b-1785fb3001b9","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","volume":25,"labwareId":"01ab8b91-996c-41a2-a11e-57719913979e:opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1","wellName":"A3","wellLocation":{"origin":"bottom","offset":{"z":0.5}},"flowRate":46.43}},{"commandType":"dropTip","key":"f1816015-6ada-48e7-b879-4a2ea647339e","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","labwareId":"fixedTrash","wellName":"A1"}},{"commandType":"pickUpTip","key":"f731b034-77de-4a42-bf48-3bb52b28bd45","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","labwareId":"a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1","wellName":"B3"}},{"commandType":"aspirate","key":"0abfe1b2-89a4-4e6c-8078-a811dace2224","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","volume":25,"labwareId":"bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1","wellName":"A1","wellLocation":{"origin":"bottom","offset":{"z":1}},"flowRate":46.43}},{"commandType":"dispense","key":"961ab4c8-da15-4350-ae65-470efc9b2238","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","volume":25,"labwareId":"01ab8b91-996c-41a2-a11e-57719913979e:opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1","wellName":"B3","wellLocation":{"origin":"bottom","offset":{"z":0.5}},"flowRate":46.43}},{"commandType":"dropTip","key":"cbd55095-b432-41eb-ab53-109553e27b6a","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","labwareId":"fixedTrash","wellName":"A1"}},{"commandType":"pickUpTip","key":"2144b06e-e692-466d-a802-6f60db8d6df3","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","labwareId":"a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1","wellName":"C3"}},{"commandType":"aspirate","key":"fc30f4e1-2e26-4cfc-95b7-abd1cdab5add","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","volume":25,"labwareId":"bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1","wellName":"A1","wellLocation":{"origin":"bottom","offset":{"z":1}},"flowRate":46.43}},{"commandType":"dispense","key":"81707a0d-d590-4c95-9ea2-288e61244e23","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","volume":25,"labwareId":"01ab8b91-996c-41a2-a11e-57719913979e:opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1","wellName":"C3","wellLocation":{"origin":"bottom","offset":{"z":0.5}},"flowRate":46.43}},{"commandType":"dropTip","key":"e86624e9-17b4-4e4c-a818-99aa3b7203b4","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","labwareId":"fixedTrash","wellName":"A1"}},{"commandType":"pickUpTip","key":"05753124-aa01-48c8-805f-ff3c76b50ad2","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","labwareId":"a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1","wellName":"D3"}},{"commandType":"aspirate","key":"e56550a7-3894-4060-b8e9-6133aba946de","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","volume":25,"labwareId":"bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1","wellName":"A1","wellLocation":{"origin":"bottom","offset":{"z":1}},"flowRate":46.43}},{"commandType":"dispense","key":"b241d60c-4cec-4a73-b9c4-d787747125f5","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","volume":25,"labwareId":"01ab8b91-996c-41a2-a11e-57719913979e:opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1","wellName":"D3","wellLocation":{"origin":"bottom","offset":{"z":0.5}},"flowRate":46.43}},{"commandType":"dropTip","key":"3df64ca9-dc43-4eb6-94b6-09ad696e3e2e","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","labwareId":"fixedTrash","wellName":"A1"}},{"commandType":"pickUpTip","key":"7d471a9a-2a78-4cab-85d9-ef537f01135e","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","labwareId":"a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1","wellName":"E3"}},{"commandType":"aspirate","key":"1ebef344-1ba8-40dc-b233-c71095d643a1","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","volume":22,"labwareId":"bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1","wellName":"A1","wellLocation":{"origin":"bottom","offset":{"z":1}},"flowRate":46.43}},{"commandType":"dispense","key":"aee40692-f291-49f5-bb64-051378a356c7","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","volume":22,"labwareId":"111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1","wellName":"A7","wellLocation":{"origin":"bottom","offset":{"z":0.5}},"flowRate":46.43}},{"commandType":"dropTip","key":"12e5aed2-bcca-4b5b-968b-9cce7d9cb6c7","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","labwareId":"fixedTrash","wellName":"A1"}},{"commandType":"pickUpTip","key":"676d87a5-ed43-48b6-9fd7-b17fff53c880","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","labwareId":"a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1","wellName":"F3"}},{"commandType":"aspirate","key":"5adde3d5-486c-479a-a629-4fd1cd87fa55","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","volume":22,"labwareId":"bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1","wellName":"A1","wellLocation":{"origin":"bottom","offset":{"z":1}},"flowRate":46.43}},{"commandType":"dispense","key":"c21b4b82-8815-4515-9fa4-7097dec1bae2","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","volume":22,"labwareId":"111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1","wellName":"B7","wellLocation":{"origin":"bottom","offset":{"z":0.5}},"flowRate":46.43}},{"commandType":"dropTip","key":"cb2f4bdf-a782-4a68-8bbd-75b65d850d0f","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","labwareId":"fixedTrash","wellName":"A1"}},{"commandType":"pickUpTip","key":"aed095a1-b724-40f8-a1d9-f24820f168ef","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","labwareId":"a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1","wellName":"G3"}},{"commandType":"aspirate","key":"046acfb4-c45e-473c-bfce-7a213e8f2974","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","volume":22,"labwareId":"bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1","wellName":"A1","wellLocation":{"origin":"bottom","offset":{"z":1}},"flowRate":46.43}},{"commandType":"dispense","key":"56c2571e-dde2-4d24-9337-9003e81bee74","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","volume":22,"labwareId":"111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1","wellName":"C7","wellLocation":{"origin":"bottom","offset":{"z":0.5}},"flowRate":46.43}},{"commandType":"dropTip","key":"f1f78069-805a-4db6-90d6-cb81e937d763","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","labwareId":"fixedTrash","wellName":"A1"}},{"commandType":"pickUpTip","key":"daa6b107-d891-4a54-9d68-61fc7a1e3107","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","labwareId":"a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1","wellName":"H3"}},{"commandType":"aspirate","key":"cd45c8ac-3dd7-4d86-b613-9fcd6f7d5542","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","volume":22,"labwareId":"bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1","wellName":"A1","wellLocation":{"origin":"bottom","offset":{"z":1}},"flowRate":46.43}},{"commandType":"dispense","key":"638e754d-5b83-40c0-a6da-3fcdf5da9dda","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","volume":22,"labwareId":"111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1","wellName":"A8","wellLocation":{"origin":"bottom","offset":{"z":0.5}},"flowRate":46.43}},{"commandType":"dropTip","key":"a4fbcb43-71a0-4794-84fe-39a01fb6c5e4","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","labwareId":"fixedTrash","wellName":"A1"}},{"commandType":"pickUpTip","key":"c6d2672b-fcaa-4ff1-a12b-7d9b4fd5d89e","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","labwareId":"a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1","wellName":"A4"}},{"commandType":"aspirate","key":"590a191d-51ab-4915-a1a4-944bb8142356","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","volume":22,"labwareId":"bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1","wellName":"A1","wellLocation":{"origin":"bottom","offset":{"z":1}},"flowRate":46.43}},{"commandType":"dispense","key":"edac7a4f-a283-475c-8c59-bbf91a26c7f3","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","volume":22,"labwareId":"111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1","wellName":"B8","wellLocation":{"origin":"bottom","offset":{"z":0.5}},"flowRate":46.43}},{"commandType":"dropTip","key":"d1f57a8a-040d-4f1d-996a-b8b612ee8fe7","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","labwareId":"fixedTrash","wellName":"A1"}},{"commandType":"pickUpTip","key":"703ed8a5-52d8-45a4-a2e3-965c042b0491","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","labwareId":"a4fcf5a6-78d6-421a-8e01-2b479f430eb8:opentrons/opentrons_96_tiprack_300ul/1","wellName":"B4"}},{"commandType":"aspirate","key":"04316379-9994-4d5b-ac86-99fb532eefb5","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","volume":22,"labwareId":"bb461a1a-e444-460d-b2d6-82c15a59ecea:opentrons/agilent_1_reservoir_290ml/1","wellName":"A1","wellLocation":{"origin":"bottom","offset":{"z":1}},"flowRate":46.43}},{"commandType":"dispense","key":"3a8ea7f4-fc66-4654-ba04-dbd9f221e6a7","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","volume":22,"labwareId":"111a749b-6958-4d7a-8206-1451fbee73fc:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1","wellName":"C8","wellLocation":{"origin":"bottom","offset":{"z":0.5}},"flowRate":46.43}},{"commandType":"dropTip","key":"09d2d84e-f07b-4459-b0fe-b0216d254008","params":{"pipetteId":"1b766d4d-ba31-42cc-a49a-73e9d8c67aca","labwareId":"fixedTrash","wellName":"A1"}},{"commandType":"thermocycler/closeLid","key":"a2fc04dc-f0bf-4b71-a5fb-1334c98197ef","params":{"moduleId":"a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType"}},{"commandType":"thermocycler/setTargetBlockTemperature","key":"d08d218d-1fc4-40c2-9d19-96adcbb9736e","params":{"moduleId":"a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType","celsius":55}},{"commandType":"thermocycler/waitForBlockTemperature","key":"20955b73-7ec4-4170-a05f-329aefefc1ad","params":{"moduleId":"a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType"}},{"commandType":"thermocycler/setTargetLidTemperature","key":"16621d7f-c322-493b-9d2b-b2a90a685ed0","params":{"moduleId":"a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType","celsius":50}},{"commandType":"thermocycler/waitForLidTemperature","key":"50451d2b-8f9a-4101-b6ad-e3308d492276","params":{"moduleId":"a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType"}},{"commandType":"heaterShaker/closeLabwareLatch","key":"c4232439-eaf7-4e03-a834-35949ebceced","params":{"moduleId":"5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType"}},{"commandType":"heaterShaker/setTargetTemperature","key":"c055f48a-6e1f-40e7-a254-b1e379c8ff43","params":{"moduleId":"5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType","celsius":55}},{"commandType":"heaterShaker/waitForTemperature","key":"be5b2593-b645-4b0f-9593-c0186d5a340d","params":{"moduleId":"5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType"}},{"commandType":"heaterShaker/setAndWaitForShakeSpeed","key":"bf177287-c03d-4ba6-b8ab-27eb63d58dc4","params":{"moduleId":"5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType","rpm":1000}},{"commandType":"heaterShaker/waitForTemperature","key":"a08dddce-7364-44c9-bce7-8e7ecb0f35c2","params":{"moduleId":"5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType"}},{"commandType":"magneticModule/engage","key":"b1b75cbb-e388-4f3a-aa0f-297ecadf1ae4","params":{"moduleId":"8d4683d0-7a88-4b33-9363-bd3894a71f9a:magneticModuleType","height":12}},{"commandType":"temperatureModule/setTargetTemperature","key":"8d2e3b47-7396-4c30-aa08-4b590bcbc967","params":{"moduleId":"b5df8f5c-9fc5-4d45-98c2-0ce6bd218fda:temperatureModuleType","celsius":80}},{"commandType":"heaterShaker/waitForTemperature","key":"39aba9eb-2506-4ecf-9c98-adcfd0e7aac6","params":{"moduleId":"5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType"}},{"commandType":"heaterShaker/openLabwareLatch","key":"675eb8be-6c85-4204-9c87-d7fdd522f580","params":{"moduleId":"5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType"}},{"commandType":"heaterShaker/deactivateHeater","key":"89eb894c-fbd1-4748-997b-eafc3d2e6feb","params":{"moduleId":"5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType"}},{"commandType":"heaterShaker/deactivateShaker","key":"7500052e-ea05-4ed7-ac2b-691890d96d5c","params":{"moduleId":"5cf778e4-1131-446b-b1b4-fcc475017fa3:heaterShakerModuleType"}},{"commandType":"thermocycler/openLid","key":"a9f540e3-209d-4dbf-8abc-31dde947f317","params":{"moduleId":"a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType"}},{"commandType":"thermocycler/deactivateBlock","key":"d029e789-dcc4-4f56-a306-1098b34bce3e","params":{"moduleId":"a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType"}},{"commandType":"thermocycler/deactivateLid","key":"b8fb1676-e65b-47fd-aa2a-1b447d26820f","params":{"moduleId":"a54c246e-837a-4cde-94dd-4872b0c5c032:thermocyclerModuleType"}}]} \ No newline at end of file diff --git a/app-testing/files/protocols/py/Flex_None_None_TC_2_14_verifyThermocyclerLoadedSlots.py b/app-testing/files/protocols/py/Flex_None_None_TC_2_14_verifyThermocyclerLoadedSlots.py deleted file mode 100644 index 37705eb1695..00000000000 --- a/app-testing/files/protocols/py/Flex_None_None_TC_2_14_verifyThermocyclerLoadedSlots.py +++ /dev/null @@ -1,14 +0,0 @@ -# Pulled from: https://github.com/Opentrons/opentrons/pull/14491 - - -requirements = { - "robotType": "Flex", - "apiLevel": "2.14", -} - - -def run(protocol): - thermocycler = protocol.load_module("thermocycler module gen2") - - assert protocol.loaded_modules == {"B1": thermocycler} - assert protocol.deck["A1"] == thermocycler diff --git a/app-testing/locators.py b/app-testing/locators.py index 31869355139..9218cb8f9e4 100644 --- a/app-testing/locators.py +++ b/app-testing/locators.py @@ -3,6 +3,7 @@ pipenv run python -i locators.py This launches the installed app. """ + import importlib import os diff --git a/app-testing/mypy.ini b/app-testing/mypy.ini new file mode 100644 index 00000000000..cab126eb42d --- /dev/null +++ b/app-testing/mypy.ini @@ -0,0 +1,17 @@ +[mypy] +strict = true +follow_imports = silent +warn_redundant_casts = true +warn_unused_ignores = true +disallow_any_generics = true +check_untyped_defs = true +no_implicit_reexport = true +exclude = "__init__.py" +python_version = 3.12 +plugins = pydantic.mypy + +[pydantic-mypy] +warn_untyped_fields = True + +[mypy-selenium] +ignore_missing_imports = true diff --git a/app-testing/print_protocols.py b/app-testing/print_protocols.py deleted file mode 100644 index e064f44d883..00000000000 --- a/app-testing/print_protocols.py +++ /dev/null @@ -1,30 +0,0 @@ -# pipenv run python print_protocols.py -import pathlib - -import rich -from automation.data.protocols import Protocols -from rich.panel import Panel - -stems = [p.stem for p in pathlib.Path(pathlib.Path.cwd(), "files", "protocols").rglob("*") if p.is_file()] -sorted_stems = sorted(stems) -rich.print(Panel("For protocol_files.names")) -rich.print(sorted_stems) -rich.print(Panel("Formatted for .env")) -rich.print(", ".join(sorted_stems)) -rich.print(Panel("What are actually defined?")) -protocols = Protocols() -props = [prop for prop in dir(protocols) if "__" not in prop] -rich.print(",\n".join(props)) - -possible = set(sorted_stems) -actual = set(props) -missing_protocols = possible - actual -orphan_protocols = actual - possible -rich.print(Panel("Are all protocols mapped?")) -if len(missing_protocols) == 0 and len(orphan_protocols) == 0: - rich.print("🥳 everything is mapped.") -else: - rich.print("The below protocols need to be mapped in protocols.py:") - rich.print(missing_protocols) - rich.print("\nThe below protocols are mapped in protocols.py, but don't exist in the protocols dir:") - rich.print(orphan_protocols) diff --git a/app-testing/pyproject.toml b/app-testing/pyproject.toml index 273fc00740d..336f1a0de93 100644 --- a/app-testing/pyproject.toml +++ b/app-testing/pyproject.toml @@ -3,10 +3,15 @@ line-length = 140 target-version = ['py312'] [tool.ruff] +# Like Black line-length = 140 +# Like Black +indent-width = 4 target-version = "py312" exclude = ["files"] -src = ["*.py", "automation", "tests"] +src = ["*.py", "automation", "tests", "citools"] + +[tool.ruff.lint] select = [ "E", # pycodestyle errors "W", # pycodestyle warnings @@ -15,20 +20,20 @@ select = [ "C", # flake8-comprehensions "B", # flake8-bugbear ] +fixable = ["ALL"] -[tool.ruff.per-file-ignores] -"automation/driver/base.py" = ["B008"] +[tool.ruff.format] +# Like Black, use double quotes for strings. +quote-style = "double" + +# Like Black, indent with spaces, rather than tabs. +indent-style = "space" -[tool.mypy] -strict = true -follow_imports = "silent" -warn_redundant_casts = true -warn_unused_ignores = true -disallow_any_generics = true -check_untyped_defs = true -no_implicit_reexport = true -exclude = "__init__.py" -python_version = "3.12" +# Like Black, respect magic trailing commas. +skip-magic-trailing-comma = false -[mypy-selenium] -ignore_missing_imports = true +# Like Black, automatically detect the appropriate line ending. +line-ending = "auto" + +[tool.ruff.lint.per-file-ignores] +"automation/driver/base.py" = ["B008"] diff --git a/app-testing/pytest.ini b/app-testing/pytest.ini index 5bdb3486d34..a914ee98e3c 100644 --- a/app-testing/pytest.ini +++ b/app-testing/pytest.ini @@ -1,4 +1,4 @@ [pytest] generate_report_on_test = True junit_family = legacy -addopts = --junitxml=results/results.xml --log-cli-level info --html=results/report.html --self-contained-html +addopts = -s -vv --junitxml=results/results.xml --log-cli-level info --html=results/report.html --self-contained-html diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[5887e734b5][OT2_P10S_P300M_TC1_TM_MM_2_11_Swift].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[004ebb2b82][OT2_S_v2_11_P10S_P300M_MM_TC1_TM_Swift].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[5887e734b5][OT2_P10S_P300M_TC1_TM_MM_2_11_Swift].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[004ebb2b82][OT2_S_v2_11_P10S_P300M_MM_TC1_TM_Swift].json index 4895a857732..3417b861aee 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[5887e734b5][OT2_P10S_P300M_TC1_TM_MM_2_11_Swift].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[004ebb2b82][OT2_S_v2_11_P10S_P300M_MM_TC1_TM_Swift].json @@ -14171,7 +14171,7 @@ "errors": [], "files": [ { - "name": "OT2_P10S_P300M_TC1_TM_MM_2_11_Swift.py", + "name": "OT2_S_v2_11_P10S_P300M_MM_TC1_TM_Swift.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0f71566d05][OT2_P20S_None_2_7_Walkthrough].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[011481812b][OT2_S_v2_7_P20S_None_Walkthrough].json similarity index 80% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0f71566d05][OT2_P20S_None_2_7_Walkthrough].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[011481812b][OT2_S_v2_7_P20S_None_Walkthrough].json index e52cb9863b1..00b66fb4ffe 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0f71566d05][OT2_P20S_None_2_7_Walkthrough].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[011481812b][OT2_S_v2_7_P20S_None_Walkthrough].json @@ -3253,19 +3253,852 @@ }, "status": "succeeded" }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 6.666666666666667, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666667 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Delaying for 0 minutes and 5.0 seconds", + "legacyCommandType": "command.DELAY" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 13.333333333333334, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 13.333333333333334 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 4.444444444444445, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 4.444444444444445 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 6.666666666666667, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666667 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Delaying for 0 minutes and 5.0 seconds", + "legacyCommandType": "command.DELAY" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 13.333333333333334, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 13.333333333333334 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 4.444444444444445, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 4.444444444444445 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 6.666666666666667, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666667 + }, + "status": "succeeded" + }, { "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Delaying for 0 minutes and 5.0 seconds", + "legacyCommandType": "command.DELAY" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 13.333333333333334, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 13.333333333333334 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 1.6666666666666667, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 1.6666666666666667 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], "params": { - "legacyCommandText": "Air gap", - "legacyCommandType": "command.AIR_GAP" + "flowRate": 15.12, + "volume": 2.5, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 2.5 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 1.6666666666666667, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 1.6666666666666667 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 2.5, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 2.5 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Delaying for 0 minutes and 5.0 seconds", + "legacyCommandType": "command.DELAY" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 7.56, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "dropTip", + "notes": [], + "params": { + "alternateDropLocation": false, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "default" + }, + "wellName": "B1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "pickUpTip", + "notes": [], + "params": { + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "C1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "tipDiameter": 0, + "tipLength": 30.950000000000003, + "tipVolume": 20 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 1.6666666666666667, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 1.6666666666666667 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 1.6666666666666667, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "B1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 1.6666666666666667 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 1.6666666666666667, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "C1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 1.6666666666666667 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 1.6666666666666667, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "D1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 1.6666666666666667 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 1.6666666666666667, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "E1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 1.6666666666666667 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 1.6666666666666667, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "F1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 1.6666666666666667 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 1.6666666666666667, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "G1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 1.6666666666666667 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 1.6666666666666667, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "H1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 1.6666666666666667 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 13.333333333333332, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 13.333333333333332 + }, + "status": "succeeded" + }, + { + "commandType": "dropTip", + "notes": [], + "params": { + "alternateDropLocation": false, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "default" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "pickUpTip", + "notes": [], + "params": { + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "B1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "tipDiameter": 0, + "tipLength": 30.950000000000003, + "tipVolume": 20 }, - "status": "running" + "status": "succeeded" }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 15.12, - "volume": 6.666666666666667, + "volume": 14.333333333333332, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 14.333333333333332 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 1.6666666666666667, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 1.6666666666666667 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 1.6666666666666667, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "B1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 1.6666666666666667 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 1.6666666666666667, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "C1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 1.6666666666666667 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 1.6666666666666667, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "D1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 1.6666666666666667 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 1.6666666666666667, "wellLocation": { "offset": { "x": 0, @@ -3274,9 +4107,143 @@ }, "origin": "top" }, + "wellName": "E1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 1.6666666666666667 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 1.6666666666666667, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "F1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 1.6666666666666667 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 1.6666666666666667, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "G1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 1.6666666666666667 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 15.12, + "volume": 1.6666666666666667, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "H1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 1.6666666666666667 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 7.56, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "dropTip", + "notes": [], + "params": { + "alternateDropLocation": false, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "default" + }, "wellName": "A1" }, - "status": "running" + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" } ], "config": { @@ -3286,22 +4253,10 @@ ], "protocolType": "python" }, - "errors": [ - { - "detail": "AssertionError", - "errorCode": "4000", - "errorInfo": { - "args": "()", - "class": "AssertionError", - "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/protocol_engine.py\", line 442, in finish\n await exit_stack.aclose()\n\n File \"/usr/local/lib/python3.10/contextlib.py\", line 656, in aclose\n await self.__aexit__(None, None, None)\n\n File \"/usr/local/lib/python3.10/contextlib.py\", line 714, in __aexit__\n raise exc_details[1]\n\n File \"/usr/local/lib/python3.10/contextlib.py\", line 697, in __aexit__\n cb_suppress = await cb(*exc_details)\n\n File \"/usr/local/lib/python3.10/contextlib.py\", line 608, in _exit_wrapper\n await callback(*args, **kwds)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/plugins.py\", line 102, in stop\n await p.teardown()\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_runner/legacy_context_plugin.py\", line 112, in teardown\n await self._action_dispatching_task\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_runner/legacy_context_plugin.py\", line 160, in _dispatch_all_actions\n self.dispatch(action)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/plugins.py\", line 37, in dispatch\n return self._action_dispatcher.dispatch(action)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/actions/action_dispatcher.py\", line 30, in dispatch\n self._sink.handle_action(action)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/state/state.py\", line 207, in handle_action\n substore.handle_action(action)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/state/commands.py\", line 257, in handle_action\n self._state.command_history.set_command_running(running_command)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/state/command_history.py\", line 175, in set_command_running\n assert self.get_running_command() is None\n" - }, - "errorType": "PythonException", - "wrappedErrors": [] - } - ], + "errors": [], "files": [ { - "name": "OT2_P20S_None_2_7_Walkthrough.py", + "name": "OT2_S_v2_7_P20S_None_Walkthrough.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a01dac3953][Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoFixtures].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0190369ce5][Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_DeckConfiguration1NoFixtures].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a01dac3953][Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoFixtures].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0190369ce5][Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_DeckConfiguration1NoFixtures].json index f478b321c65..c8790ada894 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a01dac3953][Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoFixtures].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0190369ce5][Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_DeckConfiguration1NoFixtures].json @@ -10424,7 +10424,7 @@ "errors": [], "files": [ { - "name": "Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoFixtures.py", + "name": "Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_DeckConfiguration1NoFixtures.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[aaab7be350][OT2_P300M_P20S_2_16_aspirateDispenseMix0Volume].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0256665840][OT2_S_v2_16_P300M_P20S_aspirateDispenseMix0Volume].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[aaab7be350][OT2_P300M_P20S_2_16_aspirateDispenseMix0Volume].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0256665840][OT2_S_v2_16_P300M_P20S_aspirateDispenseMix0Volume].json index da67ad1f73c..e9ad117dd38 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[aaab7be350][OT2_P300M_P20S_2_16_aspirateDispenseMix0Volume].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0256665840][OT2_S_v2_16_P300M_P20S_aspirateDispenseMix0Volume].json @@ -2775,7 +2775,7 @@ "errors": [], "files": [ { - "name": "OT2_P300M_P20S_2_16_aspirateDispenseMix0Volume.py", + "name": "OT2_S_v2_16_P300M_P20S_aspirateDispenseMix0Volume.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[cf3e610e54][OT2_P300M_P20S_TC_HS_TM_2_15_dispense_changes].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[041ad55e7b][OT2_S_v2_15_P300M_P20S_HS_TC_TM_dispense_changes].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[cf3e610e54][OT2_P300M_P20S_TC_HS_TM_2_15_dispense_changes].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[041ad55e7b][OT2_S_v2_15_P300M_P20S_HS_TC_TM_dispense_changes].json index 77bc98f5457..ab7e1ecff2e 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[cf3e610e54][OT2_P300M_P20S_TC_HS_TM_2_15_dispense_changes].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[041ad55e7b][OT2_S_v2_15_P300M_P20S_HS_TC_TM_dispense_changes].json @@ -2965,7 +2965,7 @@ "errors": [], "files": [ { - "name": "OT2_P300M_P20S_TC_HS_TM_2_15_dispense_changes.py", + "name": "OT2_S_v2_15_P300M_P20S_HS_TC_TM_dispense_changes.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[8d6b8b90fd][OT2_None_None_TC_2_14_VerifyThermocyclerLoadedSlots].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[09ba51132a][OT2_S_v2_14_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots].json similarity index 98% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[8d6b8b90fd][OT2_None_None_TC_2_14_VerifyThermocyclerLoadedSlots].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[09ba51132a][OT2_S_v2_14_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots].json index 7184a2d4598..73d929454d4 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[8d6b8b90fd][OT2_None_None_TC_2_14_VerifyThermocyclerLoadedSlots].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[09ba51132a][OT2_S_v2_14_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots].json @@ -127,7 +127,7 @@ "errors": [], "files": [ { - "name": "OT2_None_None_TC_2_14_VerifyThermocyclerLoadedSlots.py", + "name": "OT2_S_v2_14_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0ac062e151][OT2_P20S_P300M_HS_6_1_HS_WithCollision_Error].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0ac062e151][OT2_P20S_P300M_HS_6_1_HS_WithCollision_Error].json deleted file mode 100644 index 5667321899b..00000000000 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0ac062e151][OT2_P20S_P300M_HS_6_1_HS_WithCollision_Error].json +++ /dev/null @@ -1,5336 +0,0 @@ -{ - "commands": [ - { - "commandType": "home", - "notes": [], - "params": {}, - "result": {}, - "status": "succeeded" - }, - { - "commandType": "loadPipette", - "notes": [], - "params": { - "mount": "left", - "pipetteName": "p300_single_gen2" - }, - "result": {}, - "status": "succeeded" - }, - { - "commandType": "loadPipette", - "notes": [], - "params": { - "mount": "right", - "pipetteName": "p300_multi_gen2" - }, - "result": {}, - "status": "succeeded" - }, - { - "commandType": "loadModule", - "notes": [], - "params": { - "location": { - "slotName": "1" - }, - "model": "heaterShakerModuleV1" - }, - "result": { - "definition": { - "calibrationPoint": { - "x": 12.0, - "y": 8.75, - "z": 68.275 - }, - "compatibleWith": [], - "dimensions": { - "bareOverallHeight": 82.0, - "overLabwareHeight": 0.0 - }, - "displayName": "Heater-Shaker Module GEN1", - "gripperOffsets": { - "default": { - "dropOffset": { - "x": 0.0, - "y": 0.0, - "z": 1.0 - }, - "pickUpOffset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - } - } - }, - "labwareOffset": { - "x": -0.125, - "y": 1.125, - "z": 68.275 - }, - "model": "heaterShakerModuleV1", - "moduleType": "heaterShakerModuleType", - "otSharedSchema": "module/schemas/2", - "quirks": [], - "slotTransforms": { - "ot2_short_trash": { - "3": { - "labwareOffset": [ - [ - -1, - 0, - 0, - 0 - ], - [ - -1, - 0, - 0, - 0 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - }, - "6": { - "labwareOffset": [ - [ - -1, - 0, - 0, - 0 - ], - [ - -1, - 0, - 0, - 0 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - }, - "9": { - "labwareOffset": [ - [ - -1, - 0, - 0, - 0 - ], - [ - -1, - 0, - 0, - 0 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - } - }, - "ot2_standard": { - "3": { - "labwareOffset": [ - [ - -1, - 0, - 0, - 0 - ], - [ - -1, - 0, - 0, - 0 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - }, - "6": { - "labwareOffset": [ - [ - -1, - 0, - 0, - 0 - ], - [ - -1, - 0, - 0, - 0 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - }, - "9": { - "labwareOffset": [ - [ - -1, - 0, - 0, - 0 - ], - [ - -1, - 0, - 0, - 0 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - } - }, - "ot3_standard": { - "A1": { - "labwareOffset": [ - [ - -49.325, - 0, - 0, - 1 - ], - [ - -1.125, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.125, - 1 - ] - ] - }, - "A3": { - "labwareOffset": [ - [ - -49.325, - 0, - 0, - 1 - ], - [ - -1.125, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.125, - 1 - ] - ] - }, - "B1": { - "labwareOffset": [ - [ - -49.325, - 0, - 0, - 1 - ], - [ - -1.125, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.125, - 1 - ] - ] - }, - "B3": { - "labwareOffset": [ - [ - -49.325, - 0, - 0, - 1 - ], - [ - -1.125, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.125, - 1 - ] - ] - }, - "C1": { - "labwareOffset": [ - [ - -49.325, - 0, - 0, - 1 - ], - [ - -1.125, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.125, - 1 - ] - ] - }, - "C3": { - "labwareOffset": [ - [ - -49.325, - 0, - 0, - 1 - ], - [ - -1.125, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.125, - 1 - ] - ] - }, - "D1": { - "labwareOffset": [ - [ - -49.325, - 0, - 0, - 1 - ], - [ - -1.125, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.125, - 1 - ] - ] - }, - "D3": { - "labwareOffset": [ - [ - -49.325, - 0, - 0, - 1 - ], - [ - -1.125, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.125, - 1 - ] - ] - } - } - } - }, - "model": "heaterShakerModuleV1" - }, - "status": "succeeded" - }, - { - "commandType": "loadLabware", - "notes": [], - "params": { - "displayName": "Opentrons 96 Tip Rack 300 µL", - "loadName": "opentrons_96_tiprack_300ul", - "location": { - "slotName": "2" - }, - "namespace": "opentrons", - "version": 1 - }, - "result": { - "definition": { - "allowedRoles": [], - "brand": { - "brand": "Opentrons", - "brandId": [], - "links": [ - "https://shop.opentrons.com/collections/opentrons-tips/products/opentrons-300ul-tips" - ] - }, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - }, - "dimensions": { - "xDimension": 127.76, - "yDimension": 85.48, - "zDimension": 64.49 - }, - "gripperOffsets": {}, - "groups": [ - { - "metadata": {}, - "wells": [ - "A1", - "A10", - "A11", - "A12", - "A2", - "A3", - "A4", - "A5", - "A6", - "A7", - "A8", - "A9", - "B1", - "B10", - "B11", - "B12", - "B2", - "B3", - "B4", - "B5", - "B6", - "B7", - "B8", - "B9", - "C1", - "C10", - "C11", - "C12", - "C2", - "C3", - "C4", - "C5", - "C6", - "C7", - "C8", - "C9", - "D1", - "D10", - "D11", - "D12", - "D2", - "D3", - "D4", - "D5", - "D6", - "D7", - "D8", - "D9", - "E1", - "E10", - "E11", - "E12", - "E2", - "E3", - "E4", - "E5", - "E6", - "E7", - "E8", - "E9", - "F1", - "F10", - "F11", - "F12", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - "F8", - "F9", - "G1", - "G10", - "G11", - "G12", - "G2", - "G3", - "G4", - "G5", - "G6", - "G7", - "G8", - "G9", - "H1", - "H10", - "H11", - "H12", - "H2", - "H3", - "H4", - "H5", - "H6", - "H7", - "H8", - "H9" - ] - } - ], - "metadata": { - "displayCategory": "tipRack", - "displayName": "Opentrons 96 Tip Rack 300 µL", - "displayVolumeUnits": "µL", - "tags": [] - }, - "namespace": "opentrons", - "ordering": [ - [ - "A1", - "B1", - "C1", - "D1", - "E1", - "F1", - "G1", - "H1" - ], - [ - "A10", - "B10", - "C10", - "D10", - "E10", - "F10", - "G10", - "H10" - ], - [ - "A11", - "B11", - "C11", - "D11", - "E11", - "F11", - "G11", - "H11" - ], - [ - "A12", - "B12", - "C12", - "D12", - "E12", - "F12", - "G12", - "H12" - ], - [ - "A2", - "B2", - "C2", - "D2", - "E2", - "F2", - "G2", - "H2" - ], - [ - "A3", - "B3", - "C3", - "D3", - "E3", - "F3", - "G3", - "H3" - ], - [ - "A4", - "B4", - "C4", - "D4", - "E4", - "F4", - "G4", - "H4" - ], - [ - "A5", - "B5", - "C5", - "D5", - "E5", - "F5", - "G5", - "H5" - ], - [ - "A6", - "B6", - "C6", - "D6", - "E6", - "F6", - "G6", - "H6" - ], - [ - "A7", - "B7", - "C7", - "D7", - "E7", - "F7", - "G7", - "H7" - ], - [ - "A8", - "B8", - "C8", - "D8", - "E8", - "F8", - "G8", - "H8" - ], - [ - "A9", - "B9", - "C9", - "D9", - "E9", - "F9", - "G9", - "H9" - ] - ], - "parameters": { - "format": "96Standard", - "isMagneticModuleCompatible": false, - "isTiprack": true, - "loadName": "opentrons_96_tiprack_300ul", - "tipLength": 59.3, - "tipOverlap": 7.47 - }, - "schemaVersion": 2, - "stackingOffsetWithLabware": {}, - "stackingOffsetWithModule": {}, - "version": 1, - "wells": { - "A1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 74.24, - "z": 5.39 - }, - "A10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 74.24, - "z": 5.39 - }, - "A11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 74.24, - "z": 5.39 - }, - "A12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 74.24, - "z": 5.39 - }, - "A2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 74.24, - "z": 5.39 - }, - "A3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 74.24, - "z": 5.39 - }, - "A4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 74.24, - "z": 5.39 - }, - "A5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 74.24, - "z": 5.39 - }, - "A6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 74.24, - "z": 5.39 - }, - "A7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 74.24, - "z": 5.39 - }, - "A8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 74.24, - "z": 5.39 - }, - "A9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 74.24, - "z": 5.39 - }, - "B1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 65.24, - "z": 5.39 - }, - "B10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 65.24, - "z": 5.39 - }, - "B11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 65.24, - "z": 5.39 - }, - "B12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 65.24, - "z": 5.39 - }, - "B2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 65.24, - "z": 5.39 - }, - "B3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 65.24, - "z": 5.39 - }, - "B4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 65.24, - "z": 5.39 - }, - "B5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 65.24, - "z": 5.39 - }, - "B6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 65.24, - "z": 5.39 - }, - "B7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 65.24, - "z": 5.39 - }, - "B8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 65.24, - "z": 5.39 - }, - "B9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 65.24, - "z": 5.39 - }, - "C1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 56.24, - "z": 5.39 - }, - "C10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 56.24, - "z": 5.39 - }, - "C11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 56.24, - "z": 5.39 - }, - "C12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 56.24, - "z": 5.39 - }, - "C2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 56.24, - "z": 5.39 - }, - "C3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 56.24, - "z": 5.39 - }, - "C4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 56.24, - "z": 5.39 - }, - "C5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 56.24, - "z": 5.39 - }, - "C6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 56.24, - "z": 5.39 - }, - "C7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 56.24, - "z": 5.39 - }, - "C8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 56.24, - "z": 5.39 - }, - "C9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 56.24, - "z": 5.39 - }, - "D1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 47.24, - "z": 5.39 - }, - "D10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 47.24, - "z": 5.39 - }, - "D11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 47.24, - "z": 5.39 - }, - "D12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 47.24, - "z": 5.39 - }, - "D2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 47.24, - "z": 5.39 - }, - "D3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 47.24, - "z": 5.39 - }, - "D4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 47.24, - "z": 5.39 - }, - "D5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 47.24, - "z": 5.39 - }, - "D6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 47.24, - "z": 5.39 - }, - "D7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 47.24, - "z": 5.39 - }, - "D8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 47.24, - "z": 5.39 - }, - "D9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 47.24, - "z": 5.39 - }, - "E1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 38.24, - "z": 5.39 - }, - "E10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 38.24, - "z": 5.39 - }, - "E11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 38.24, - "z": 5.39 - }, - "E12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 38.24, - "z": 5.39 - }, - "E2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 38.24, - "z": 5.39 - }, - "E3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 38.24, - "z": 5.39 - }, - "E4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 38.24, - "z": 5.39 - }, - "E5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 38.24, - "z": 5.39 - }, - "E6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 38.24, - "z": 5.39 - }, - "E7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 38.24, - "z": 5.39 - }, - "E8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 38.24, - "z": 5.39 - }, - "E9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 38.24, - "z": 5.39 - }, - "F1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 29.24, - "z": 5.39 - }, - "F10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 29.24, - "z": 5.39 - }, - "F11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 29.24, - "z": 5.39 - }, - "F12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 29.24, - "z": 5.39 - }, - "F2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 29.24, - "z": 5.39 - }, - "F3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 29.24, - "z": 5.39 - }, - "F4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 29.24, - "z": 5.39 - }, - "F5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 29.24, - "z": 5.39 - }, - "F6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 29.24, - "z": 5.39 - }, - "F7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 29.24, - "z": 5.39 - }, - "F8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 29.24, - "z": 5.39 - }, - "F9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 29.24, - "z": 5.39 - }, - "G1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 20.24, - "z": 5.39 - }, - "G10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 20.24, - "z": 5.39 - }, - "G11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 20.24, - "z": 5.39 - }, - "G12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 20.24, - "z": 5.39 - }, - "G2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 20.24, - "z": 5.39 - }, - "G3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 20.24, - "z": 5.39 - }, - "G4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 20.24, - "z": 5.39 - }, - "G5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 20.24, - "z": 5.39 - }, - "G6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 20.24, - "z": 5.39 - }, - "G7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 20.24, - "z": 5.39 - }, - "G8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 20.24, - "z": 5.39 - }, - "G9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 20.24, - "z": 5.39 - }, - "H1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 11.24, - "z": 5.39 - }, - "H10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 11.24, - "z": 5.39 - }, - "H11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 11.24, - "z": 5.39 - }, - "H12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 11.24, - "z": 5.39 - }, - "H2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 11.24, - "z": 5.39 - }, - "H3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 11.24, - "z": 5.39 - }, - "H4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 11.24, - "z": 5.39 - }, - "H5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 11.24, - "z": 5.39 - }, - "H6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 11.24, - "z": 5.39 - }, - "H7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 11.24, - "z": 5.39 - }, - "H8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 11.24, - "z": 5.39 - }, - "H9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 11.24, - "z": 5.39 - } - } - } - }, - "status": "succeeded" - }, - { - "commandType": "loadLabware", - "notes": [], - "params": { - "displayName": "H/S", - "loadName": "opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep", - "location": {}, - "namespace": "opentrons", - "version": 1 - }, - "result": { - "definition": { - "allowedRoles": [], - "brand": { - "brand": "Opentrons", - "brandId": [], - "links": [] - }, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - }, - "dimensions": { - "xDimension": 127.6, - "yDimension": 85.3, - "zDimension": 42.25 - }, - "gripperOffsets": {}, - "groups": [ - { - "brand": { - "brand": "NEST", - "brandId": [ - "503001", - "503501" - ], - "links": [ - "https://www.nest-biotech.com/deep-well-plates/59253726.html" - ] - }, - "metadata": { - "displayCategory": "wellPlate", - "displayName": "NEST 96 Deepwell Plate 2mL", - "wellBottomShape": "v" - }, - "wells": [ - "A1", - "A10", - "A11", - "A12", - "A2", - "A3", - "A4", - "A5", - "A6", - "A7", - "A8", - "A9", - "B1", - "B10", - "B11", - "B12", - "B2", - "B3", - "B4", - "B5", - "B6", - "B7", - "B8", - "B9", - "C1", - "C10", - "C11", - "C12", - "C2", - "C3", - "C4", - "C5", - "C6", - "C7", - "C8", - "C9", - "D1", - "D10", - "D11", - "D12", - "D2", - "D3", - "D4", - "D5", - "D6", - "D7", - "D8", - "D9", - "E1", - "E10", - "E11", - "E12", - "E2", - "E3", - "E4", - "E5", - "E6", - "E7", - "E8", - "E9", - "F1", - "F10", - "F11", - "F12", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - "F8", - "F9", - "G1", - "G10", - "G11", - "G12", - "G2", - "G3", - "G4", - "G5", - "G6", - "G7", - "G8", - "G9", - "H1", - "H10", - "H11", - "H12", - "H2", - "H3", - "H4", - "H5", - "H6", - "H7", - "H8", - "H9" - ] - } - ], - "metadata": { - "displayCategory": "aluminumBlock", - "displayName": "Opentrons 96 Deep Well Adapter with NEST Deep Well Plate 2 mL", - "displayVolumeUnits": "µL", - "tags": [] - }, - "namespace": "opentrons", - "ordering": [ - [ - "A1", - "B1", - "C1", - "D1", - "E1", - "F1", - "G1", - "H1" - ], - [ - "A10", - "B10", - "C10", - "D10", - "E10", - "F10", - "G10", - "H10" - ], - [ - "A11", - "B11", - "C11", - "D11", - "E11", - "F11", - "G11", - "H11" - ], - [ - "A12", - "B12", - "C12", - "D12", - "E12", - "F12", - "G12", - "H12" - ], - [ - "A2", - "B2", - "C2", - "D2", - "E2", - "F2", - "G2", - "H2" - ], - [ - "A3", - "B3", - "C3", - "D3", - "E3", - "F3", - "G3", - "H3" - ], - [ - "A4", - "B4", - "C4", - "D4", - "E4", - "F4", - "G4", - "H4" - ], - [ - "A5", - "B5", - "C5", - "D5", - "E5", - "F5", - "G5", - "H5" - ], - [ - "A6", - "B6", - "C6", - "D6", - "E6", - "F6", - "G6", - "H6" - ], - [ - "A7", - "B7", - "C7", - "D7", - "E7", - "F7", - "G7", - "H7" - ], - [ - "A8", - "B8", - "C8", - "D8", - "E8", - "F8", - "G8", - "H8" - ], - [ - "A9", - "B9", - "C9", - "D9", - "E9", - "F9", - "G9", - "H9" - ] - ], - "parameters": { - "format": "96Standard", - "isMagneticModuleCompatible": false, - "isTiprack": false, - "loadName": "opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep", - "quirks": [] - }, - "schemaVersion": 2, - "stackingOffsetWithLabware": {}, - "stackingOffsetWithModule": {}, - "version": 1, - "wells": { - "A1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 4.25 - }, - "A10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 4.25 - }, - "A11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 4.25 - }, - "A12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 4.25 - }, - "A2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 4.25 - }, - "A3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 4.25 - }, - "A4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 4.25 - }, - "A5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 4.25 - }, - "A6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 4.25 - }, - "A7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 4.25 - }, - "A8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 4.25 - }, - "A9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 4.25 - }, - "B1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 4.25 - }, - "B10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 4.25 - }, - "B11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 4.25 - }, - "B12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 4.25 - }, - "B2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 4.25 - }, - "B3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 4.25 - }, - "B4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 4.25 - }, - "B5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 4.25 - }, - "B6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 4.25 - }, - "B7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 4.25 - }, - "B8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 4.25 - }, - "B9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 4.25 - }, - "C1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 4.25 - }, - "C10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 4.25 - }, - "C11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 4.25 - }, - "C12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 4.25 - }, - "C2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 4.25 - }, - "C3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 4.25 - }, - "C4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 4.25 - }, - "C5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 4.25 - }, - "C6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 4.25 - }, - "C7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 4.25 - }, - "C8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 4.25 - }, - "C9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 4.25 - }, - "D1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 4.25 - }, - "D10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 4.25 - }, - "D11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 4.25 - }, - "D12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 4.25 - }, - "D2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 4.25 - }, - "D3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 4.25 - }, - "D4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 4.25 - }, - "D5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 4.25 - }, - "D6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 4.25 - }, - "D7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 4.25 - }, - "D8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 4.25 - }, - "D9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 4.25 - }, - "E1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 4.25 - }, - "E10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 4.25 - }, - "E11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 4.25 - }, - "E12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 4.25 - }, - "E2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 4.25 - }, - "E3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 4.25 - }, - "E4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 4.25 - }, - "E5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 4.25 - }, - "E6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 4.25 - }, - "E7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 4.25 - }, - "E8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 4.25 - }, - "E9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 4.25 - }, - "F1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 4.25 - }, - "F10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 4.25 - }, - "F11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 4.25 - }, - "F12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 4.25 - }, - "F2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 4.25 - }, - "F3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 4.25 - }, - "F4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 4.25 - }, - "F5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 4.25 - }, - "F6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 4.25 - }, - "F7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 4.25 - }, - "F8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 4.25 - }, - "F9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 4.25 - }, - "G1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 4.25 - }, - "G10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 4.25 - }, - "G11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 4.25 - }, - "G12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 4.25 - }, - "G2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 4.25 - }, - "G3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 4.25 - }, - "G4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 4.25 - }, - "G5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 4.25 - }, - "G6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 4.25 - }, - "G7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 4.25 - }, - "G8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 4.25 - }, - "G9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 4.25 - }, - "H1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 4.25 - }, - "H10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 4.25 - }, - "H11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 4.25 - }, - "H12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 4.25 - }, - "H2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 4.25 - }, - "H3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 4.25 - }, - "H4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 4.25 - }, - "H5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 4.25 - }, - "H6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 4.25 - }, - "H7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 4.25 - }, - "H8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 4.25 - }, - "H9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 4.25 - } - } - } - }, - "status": "succeeded" - }, - { - "commandType": "loadLabware", - "notes": [], - "params": { - "displayName": "Opentrons 96 Tip Rack 300 µL (1)", - "loadName": "opentrons_96_tiprack_300ul", - "location": { - "slotName": "4" - }, - "namespace": "opentrons", - "version": 1 - }, - "result": { - "definition": { - "allowedRoles": [], - "brand": { - "brand": "Opentrons", - "brandId": [], - "links": [ - "https://shop.opentrons.com/collections/opentrons-tips/products/opentrons-300ul-tips" - ] - }, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - }, - "dimensions": { - "xDimension": 127.76, - "yDimension": 85.48, - "zDimension": 64.49 - }, - "gripperOffsets": {}, - "groups": [ - { - "metadata": {}, - "wells": [ - "A1", - "A10", - "A11", - "A12", - "A2", - "A3", - "A4", - "A5", - "A6", - "A7", - "A8", - "A9", - "B1", - "B10", - "B11", - "B12", - "B2", - "B3", - "B4", - "B5", - "B6", - "B7", - "B8", - "B9", - "C1", - "C10", - "C11", - "C12", - "C2", - "C3", - "C4", - "C5", - "C6", - "C7", - "C8", - "C9", - "D1", - "D10", - "D11", - "D12", - "D2", - "D3", - "D4", - "D5", - "D6", - "D7", - "D8", - "D9", - "E1", - "E10", - "E11", - "E12", - "E2", - "E3", - "E4", - "E5", - "E6", - "E7", - "E8", - "E9", - "F1", - "F10", - "F11", - "F12", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - "F8", - "F9", - "G1", - "G10", - "G11", - "G12", - "G2", - "G3", - "G4", - "G5", - "G6", - "G7", - "G8", - "G9", - "H1", - "H10", - "H11", - "H12", - "H2", - "H3", - "H4", - "H5", - "H6", - "H7", - "H8", - "H9" - ] - } - ], - "metadata": { - "displayCategory": "tipRack", - "displayName": "Opentrons 96 Tip Rack 300 µL", - "displayVolumeUnits": "µL", - "tags": [] - }, - "namespace": "opentrons", - "ordering": [ - [ - "A1", - "B1", - "C1", - "D1", - "E1", - "F1", - "G1", - "H1" - ], - [ - "A10", - "B10", - "C10", - "D10", - "E10", - "F10", - "G10", - "H10" - ], - [ - "A11", - "B11", - "C11", - "D11", - "E11", - "F11", - "G11", - "H11" - ], - [ - "A12", - "B12", - "C12", - "D12", - "E12", - "F12", - "G12", - "H12" - ], - [ - "A2", - "B2", - "C2", - "D2", - "E2", - "F2", - "G2", - "H2" - ], - [ - "A3", - "B3", - "C3", - "D3", - "E3", - "F3", - "G3", - "H3" - ], - [ - "A4", - "B4", - "C4", - "D4", - "E4", - "F4", - "G4", - "H4" - ], - [ - "A5", - "B5", - "C5", - "D5", - "E5", - "F5", - "G5", - "H5" - ], - [ - "A6", - "B6", - "C6", - "D6", - "E6", - "F6", - "G6", - "H6" - ], - [ - "A7", - "B7", - "C7", - "D7", - "E7", - "F7", - "G7", - "H7" - ], - [ - "A8", - "B8", - "C8", - "D8", - "E8", - "F8", - "G8", - "H8" - ], - [ - "A9", - "B9", - "C9", - "D9", - "E9", - "F9", - "G9", - "H9" - ] - ], - "parameters": { - "format": "96Standard", - "isMagneticModuleCompatible": false, - "isTiprack": true, - "loadName": "opentrons_96_tiprack_300ul", - "tipLength": 59.3, - "tipOverlap": 7.47 - }, - "schemaVersion": 2, - "stackingOffsetWithLabware": {}, - "stackingOffsetWithModule": {}, - "version": 1, - "wells": { - "A1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 74.24, - "z": 5.39 - }, - "A10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 74.24, - "z": 5.39 - }, - "A11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 74.24, - "z": 5.39 - }, - "A12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 74.24, - "z": 5.39 - }, - "A2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 74.24, - "z": 5.39 - }, - "A3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 74.24, - "z": 5.39 - }, - "A4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 74.24, - "z": 5.39 - }, - "A5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 74.24, - "z": 5.39 - }, - "A6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 74.24, - "z": 5.39 - }, - "A7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 74.24, - "z": 5.39 - }, - "A8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 74.24, - "z": 5.39 - }, - "A9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 74.24, - "z": 5.39 - }, - "B1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 65.24, - "z": 5.39 - }, - "B10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 65.24, - "z": 5.39 - }, - "B11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 65.24, - "z": 5.39 - }, - "B12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 65.24, - "z": 5.39 - }, - "B2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 65.24, - "z": 5.39 - }, - "B3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 65.24, - "z": 5.39 - }, - "B4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 65.24, - "z": 5.39 - }, - "B5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 65.24, - "z": 5.39 - }, - "B6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 65.24, - "z": 5.39 - }, - "B7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 65.24, - "z": 5.39 - }, - "B8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 65.24, - "z": 5.39 - }, - "B9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 65.24, - "z": 5.39 - }, - "C1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 56.24, - "z": 5.39 - }, - "C10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 56.24, - "z": 5.39 - }, - "C11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 56.24, - "z": 5.39 - }, - "C12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 56.24, - "z": 5.39 - }, - "C2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 56.24, - "z": 5.39 - }, - "C3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 56.24, - "z": 5.39 - }, - "C4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 56.24, - "z": 5.39 - }, - "C5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 56.24, - "z": 5.39 - }, - "C6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 56.24, - "z": 5.39 - }, - "C7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 56.24, - "z": 5.39 - }, - "C8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 56.24, - "z": 5.39 - }, - "C9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 56.24, - "z": 5.39 - }, - "D1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 47.24, - "z": 5.39 - }, - "D10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 47.24, - "z": 5.39 - }, - "D11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 47.24, - "z": 5.39 - }, - "D12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 47.24, - "z": 5.39 - }, - "D2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 47.24, - "z": 5.39 - }, - "D3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 47.24, - "z": 5.39 - }, - "D4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 47.24, - "z": 5.39 - }, - "D5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 47.24, - "z": 5.39 - }, - "D6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 47.24, - "z": 5.39 - }, - "D7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 47.24, - "z": 5.39 - }, - "D8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 47.24, - "z": 5.39 - }, - "D9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 47.24, - "z": 5.39 - }, - "E1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 38.24, - "z": 5.39 - }, - "E10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 38.24, - "z": 5.39 - }, - "E11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 38.24, - "z": 5.39 - }, - "E12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 38.24, - "z": 5.39 - }, - "E2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 38.24, - "z": 5.39 - }, - "E3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 38.24, - "z": 5.39 - }, - "E4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 38.24, - "z": 5.39 - }, - "E5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 38.24, - "z": 5.39 - }, - "E6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 38.24, - "z": 5.39 - }, - "E7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 38.24, - "z": 5.39 - }, - "E8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 38.24, - "z": 5.39 - }, - "E9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 38.24, - "z": 5.39 - }, - "F1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 29.24, - "z": 5.39 - }, - "F10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 29.24, - "z": 5.39 - }, - "F11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 29.24, - "z": 5.39 - }, - "F12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 29.24, - "z": 5.39 - }, - "F2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 29.24, - "z": 5.39 - }, - "F3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 29.24, - "z": 5.39 - }, - "F4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 29.24, - "z": 5.39 - }, - "F5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 29.24, - "z": 5.39 - }, - "F6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 29.24, - "z": 5.39 - }, - "F7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 29.24, - "z": 5.39 - }, - "F8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 29.24, - "z": 5.39 - }, - "F9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 29.24, - "z": 5.39 - }, - "G1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 20.24, - "z": 5.39 - }, - "G10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 20.24, - "z": 5.39 - }, - "G11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 20.24, - "z": 5.39 - }, - "G12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 20.24, - "z": 5.39 - }, - "G2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 20.24, - "z": 5.39 - }, - "G3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 20.24, - "z": 5.39 - }, - "G4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 20.24, - "z": 5.39 - }, - "G5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 20.24, - "z": 5.39 - }, - "G6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 20.24, - "z": 5.39 - }, - "G7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 20.24, - "z": 5.39 - }, - "G8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 20.24, - "z": 5.39 - }, - "G9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 20.24, - "z": 5.39 - }, - "H1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 11.24, - "z": 5.39 - }, - "H10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 11.24, - "z": 5.39 - }, - "H11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 11.24, - "z": 5.39 - }, - "H12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 11.24, - "z": 5.39 - }, - "H2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 11.24, - "z": 5.39 - }, - "H3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 11.24, - "z": 5.39 - }, - "H4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 11.24, - "z": 5.39 - }, - "H5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 11.24, - "z": 5.39 - }, - "H6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 11.24, - "z": 5.39 - }, - "H7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 11.24, - "z": 5.39 - }, - "H8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 11.24, - "z": 5.39 - }, - "H9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 11.24, - "z": 5.39 - } - } - } - }, - "status": "succeeded" - }, - { - "commandType": "loadLabware", - "notes": [], - "params": { - "displayName": "1", - "loadName": "armadillo_96_wellplate_200ul_pcr_full_skirt", - "location": { - "slotName": "5" - }, - "namespace": "opentrons", - "version": 1 - }, - "result": { - "definition": { - "allowedRoles": [], - "brand": { - "brand": "Thermo Scientific", - "brandId": [ - "AB2396" - ], - "links": [ - "https://www.fishersci.com/shop/products/armadillo-96-well-pcr-plate-1/AB2396" - ] - }, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - }, - "dimensions": { - "xDimension": 127.76, - "yDimension": 85.48, - "zDimension": 16 - }, - "gripperOffsets": {}, - "groups": [ - { - "metadata": { - "wellBottomShape": "v" - }, - "wells": [ - "A1", - "A10", - "A11", - "A12", - "A2", - "A3", - "A4", - "A5", - "A6", - "A7", - "A8", - "A9", - "B1", - "B10", - "B11", - "B12", - "B2", - "B3", - "B4", - "B5", - "B6", - "B7", - "B8", - "B9", - "C1", - "C10", - "C11", - "C12", - "C2", - "C3", - "C4", - "C5", - "C6", - "C7", - "C8", - "C9", - "D1", - "D10", - "D11", - "D12", - "D2", - "D3", - "D4", - "D5", - "D6", - "D7", - "D8", - "D9", - "E1", - "E10", - "E11", - "E12", - "E2", - "E3", - "E4", - "E5", - "E6", - "E7", - "E8", - "E9", - "F1", - "F10", - "F11", - "F12", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - "F8", - "F9", - "G1", - "G10", - "G11", - "G12", - "G2", - "G3", - "G4", - "G5", - "G6", - "G7", - "G8", - "G9", - "H1", - "H10", - "H11", - "H12", - "H2", - "H3", - "H4", - "H5", - "H6", - "H7", - "H8", - "H9" - ] - } - ], - "metadata": { - "displayCategory": "wellPlate", - "displayName": "Armadillo 96 Well Plate 200 µL PCR Full Skirt", - "displayVolumeUnits": "µL", - "tags": [] - }, - "namespace": "opentrons", - "ordering": [ - [ - "A1", - "B1", - "C1", - "D1", - "E1", - "F1", - "G1", - "H1" - ], - [ - "A10", - "B10", - "C10", - "D10", - "E10", - "F10", - "G10", - "H10" - ], - [ - "A11", - "B11", - "C11", - "D11", - "E11", - "F11", - "G11", - "H11" - ], - [ - "A12", - "B12", - "C12", - "D12", - "E12", - "F12", - "G12", - "H12" - ], - [ - "A2", - "B2", - "C2", - "D2", - "E2", - "F2", - "G2", - "H2" - ], - [ - "A3", - "B3", - "C3", - "D3", - "E3", - "F3", - "G3", - "H3" - ], - [ - "A4", - "B4", - "C4", - "D4", - "E4", - "F4", - "G4", - "H4" - ], - [ - "A5", - "B5", - "C5", - "D5", - "E5", - "F5", - "G5", - "H5" - ], - [ - "A6", - "B6", - "C6", - "D6", - "E6", - "F6", - "G6", - "H6" - ], - [ - "A7", - "B7", - "C7", - "D7", - "E7", - "F7", - "G7", - "H7" - ], - [ - "A8", - "B8", - "C8", - "D8", - "E8", - "F8", - "G8", - "H8" - ], - [ - "A9", - "B9", - "C9", - "D9", - "E9", - "F9", - "G9", - "H9" - ] - ], - "parameters": { - "format": "96Standard", - "isMagneticModuleCompatible": true, - "isTiprack": false, - "loadName": "armadillo_96_wellplate_200ul_pcr_full_skirt" - }, - "schemaVersion": 2, - "stackingOffsetWithLabware": {}, - "stackingOffsetWithModule": {}, - "version": 1, - "wells": { - "A1": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 74.24, - "z": 1.05 - }, - "A10": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 74.24, - "z": 1.05 - }, - "A11": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 74.24, - "z": 1.05 - }, - "A12": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 74.24, - "z": 1.05 - }, - "A2": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 74.24, - "z": 1.05 - }, - "A3": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 74.24, - "z": 1.05 - }, - "A4": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 74.24, - "z": 1.05 - }, - "A5": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 74.24, - "z": 1.05 - }, - "A6": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 74.24, - "z": 1.05 - }, - "A7": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 74.24, - "z": 1.05 - }, - "A8": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 74.24, - "z": 1.05 - }, - "A9": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 74.24, - "z": 1.05 - }, - "B1": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 65.24, - "z": 1.05 - }, - "B10": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 65.24, - "z": 1.05 - }, - "B11": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 65.24, - "z": 1.05 - }, - "B12": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 65.24, - "z": 1.05 - }, - "B2": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 65.24, - "z": 1.05 - }, - "B3": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 65.24, - "z": 1.05 - }, - "B4": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 65.24, - "z": 1.05 - }, - "B5": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 65.24, - "z": 1.05 - }, - "B6": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 65.24, - "z": 1.05 - }, - "B7": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 65.24, - "z": 1.05 - }, - "B8": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 65.24, - "z": 1.05 - }, - "B9": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 65.24, - "z": 1.05 - }, - "C1": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 56.24, - "z": 1.05 - }, - "C10": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 56.24, - "z": 1.05 - }, - "C11": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 56.24, - "z": 1.05 - }, - "C12": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 56.24, - "z": 1.05 - }, - "C2": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 56.24, - "z": 1.05 - }, - "C3": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 56.24, - "z": 1.05 - }, - "C4": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 56.24, - "z": 1.05 - }, - "C5": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 56.24, - "z": 1.05 - }, - "C6": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 56.24, - "z": 1.05 - }, - "C7": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 56.24, - "z": 1.05 - }, - "C8": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 56.24, - "z": 1.05 - }, - "C9": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 56.24, - "z": 1.05 - }, - "D1": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 47.24, - "z": 1.05 - }, - "D10": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 47.24, - "z": 1.05 - }, - "D11": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 47.24, - "z": 1.05 - }, - "D12": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 47.24, - "z": 1.05 - }, - "D2": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 47.24, - "z": 1.05 - }, - "D3": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 47.24, - "z": 1.05 - }, - "D4": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 47.24, - "z": 1.05 - }, - "D5": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 47.24, - "z": 1.05 - }, - "D6": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 47.24, - "z": 1.05 - }, - "D7": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 47.24, - "z": 1.05 - }, - "D8": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 47.24, - "z": 1.05 - }, - "D9": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 47.24, - "z": 1.05 - }, - "E1": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 38.24, - "z": 1.05 - }, - "E10": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 38.24, - "z": 1.05 - }, - "E11": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 38.24, - "z": 1.05 - }, - "E12": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 38.24, - "z": 1.05 - }, - "E2": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 38.24, - "z": 1.05 - }, - "E3": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 38.24, - "z": 1.05 - }, - "E4": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 38.24, - "z": 1.05 - }, - "E5": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 38.24, - "z": 1.05 - }, - "E6": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 38.24, - "z": 1.05 - }, - "E7": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 38.24, - "z": 1.05 - }, - "E8": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 38.24, - "z": 1.05 - }, - "E9": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 38.24, - "z": 1.05 - }, - "F1": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 29.24, - "z": 1.05 - }, - "F10": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 29.24, - "z": 1.05 - }, - "F11": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 29.24, - "z": 1.05 - }, - "F12": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 29.24, - "z": 1.05 - }, - "F2": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 29.24, - "z": 1.05 - }, - "F3": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 29.24, - "z": 1.05 - }, - "F4": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 29.24, - "z": 1.05 - }, - "F5": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 29.24, - "z": 1.05 - }, - "F6": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 29.24, - "z": 1.05 - }, - "F7": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 29.24, - "z": 1.05 - }, - "F8": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 29.24, - "z": 1.05 - }, - "F9": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 29.24, - "z": 1.05 - }, - "G1": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 20.24, - "z": 1.05 - }, - "G10": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 20.24, - "z": 1.05 - }, - "G11": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 20.24, - "z": 1.05 - }, - "G12": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 20.24, - "z": 1.05 - }, - "G2": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 20.24, - "z": 1.05 - }, - "G3": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 20.24, - "z": 1.05 - }, - "G4": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 20.24, - "z": 1.05 - }, - "G5": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 20.24, - "z": 1.05 - }, - "G6": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 20.24, - "z": 1.05 - }, - "G7": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 20.24, - "z": 1.05 - }, - "G8": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 20.24, - "z": 1.05 - }, - "G9": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 20.24, - "z": 1.05 - }, - "H1": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 14.38, - "y": 11.24, - "z": 1.05 - }, - "H10": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 95.38, - "y": 11.24, - "z": 1.05 - }, - "H11": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 104.38, - "y": 11.24, - "z": 1.05 - }, - "H12": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 113.38, - "y": 11.24, - "z": 1.05 - }, - "H2": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 23.38, - "y": 11.24, - "z": 1.05 - }, - "H3": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 32.38, - "y": 11.24, - "z": 1.05 - }, - "H4": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 41.38, - "y": 11.24, - "z": 1.05 - }, - "H5": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 50.38, - "y": 11.24, - "z": 1.05 - }, - "H6": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 59.38, - "y": 11.24, - "z": 1.05 - }, - "H7": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 68.38, - "y": 11.24, - "z": 1.05 - }, - "H8": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 77.38, - "y": 11.24, - "z": 1.05 - }, - "H9": { - "depth": 14.95, - "diameter": 5.5, - "shape": "circular", - "totalLiquidVolume": 200, - "x": 86.38, - "y": 11.24, - "z": 1.05 - } - } - } - }, - "status": "succeeded" - }, - { - "commandType": "loadLiquid", - "notes": [], - "params": { - "volumeByWell": { - "A1": 100.0, - "A2": 100.0, - "A3": 100.0, - "B1": 100.0, - "B2": 100.0, - "B3": 100.0, - "C1": 100.0, - "C2": 100.0, - "C3": 100.0, - "D1": 100.0, - "D2": 100.0, - "D3": 100.0, - "E1": 100.0, - "E2": 100.0, - "E3": 100.0, - "F1": 100.0, - "F2": 100.0, - "F3": 100.0, - "G1": 100.0, - "G2": 100.0, - "G3": 100.0, - "H1": 100.0, - "H2": 100.0, - "H3": 100.0 - } - }, - "result": {}, - "status": "succeeded" - }, - { - "commandType": "heaterShaker/closeLabwareLatch", - "notes": [], - "params": {}, - "result": {}, - "status": "succeeded" - }, - { - "commandType": "heaterShaker/deactivateHeater", - "notes": [], - "params": {}, - "result": {}, - "status": "succeeded" - }, - { - "commandType": "heaterShaker/deactivateShaker", - "notes": [], - "params": {}, - "result": {}, - "status": "succeeded" - } - ], - "config": { - "protocolType": "json", - "schemaVersion": 6 - }, - "errors": [], - "files": [ - { - "name": "OT2_P20S_P300M_HS_6_1_HS_WithCollision_Error.json", - "role": "main" - }, - { - "name": "cpx_4_tuberack_100ul.json", - "role": "labware" - }, - { - "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", - "role": "labware" - }, - { - "name": "opentrons_ot3_96_tiprack_200ul_rss.json", - "role": "labware" - }, - { - "name": "opentrons_ot3_96_tiprack_50ul_rss.json", - "role": "labware" - }, - { - "name": "sample_labware.json", - "role": "labware" - } - ], - "labware": [ - { - "definitionUri": "opentrons/opentrons_1_trash_1100ml_fixed/1", - "loadName": "opentrons_1_trash_1100ml_fixed", - "location": { - "slotName": "12" - } - }, - { - "definitionUri": "opentrons/opentrons_96_tiprack_300ul/1", - "displayName": "Opentrons 96 Tip Rack 300 µL", - "loadName": "opentrons_96_tiprack_300ul", - "location": { - "slotName": "2" - } - }, - { - "definitionUri": "opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1", - "displayName": "H/S", - "loadName": "opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep", - "location": {} - }, - { - "definitionUri": "opentrons/opentrons_96_tiprack_300ul/1", - "displayName": "Opentrons 96 Tip Rack 300 µL (1)", - "loadName": "opentrons_96_tiprack_300ul", - "location": { - "slotName": "4" - } - }, - { - "definitionUri": "opentrons/armadillo_96_wellplate_200ul_pcr_full_skirt/1", - "displayName": "1", - "loadName": "armadillo_96_wellplate_200ul_pcr_full_skirt", - "location": { - "slotName": "5" - } - } - ], - "liquids": [ - { - "description": "", - "displayColor": "#b925ff", - "displayName": "Water" - } - ], - "metadata": { - "author": "", - "category": null, - "description": "", - "protocolName": "HS Collision", - "subcategory": null, - "tags": [] - }, - "modules": [ - { - "location": { - "slotName": "1" - }, - "model": "heaterShakerModuleV1" - } - ], - "pipettes": [ - { - "mount": "left", - "pipetteName": "p300_single_gen2" - }, - { - "mount": "right", - "pipetteName": "p300_multi_gen2" - } - ], - "robotType": "OT-2 Standard", - "runTimeParameters": [] -} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0affe60373][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_maximum].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0affe60373][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_maximum].json new file mode 100644 index 00000000000..79195fd87fe --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0affe60373][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_maximum].json @@ -0,0 +1,74 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + } + ], + "config": { + "apiVersion": [ + 2, + 18 + ], + "protocolType": "python" + }, + "errors": [ + { + "detail": "ParameterDefinitionError [line 104]: Maximum is type 'str', but must be of parameter type 'int'", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ExceptionInProtocolError", + "wrappedErrors": [ + { + "detail": "opentrons.protocols.parameters.types.ParameterDefinitionError: Maximum is type 'str', but must be of parameter type 'int'", + "errorCode": "4000", + "errorInfo": { + "args": "(\"Maximum is type 'str', but must be of parameter type 'int'\",)", + "class": "ParameterDefinitionError", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 80, in _parse_and_set_parameters\n exec(\"add_parameters(__param_context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_maximum.py\", line 104, in add_parameters\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/_parameter_context.py\", line 56, in add_int\n parameter = parameter_definition.create_int_parameter(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 178, in create_int_parameter\n return ParameterDefinition(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 73, in __init__\n validation.validate_options(default, minimum, maximum, choices, parameter_type)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/validation.py\", line 266, in validate_options\n _validate_min_and_max(minimum, maximum, parameter_type)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/validation.py\", line 218, in _validate_min_and_max\n raise ParameterDefinitionError(\n" + }, + "errorType": "PythonException", + "wrappedErrors": [] + } + ] + } + ], + "files": [ + { + "name": "Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_maximum.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "protocolName": "Description Too Long 2.18" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-3 Standard", + "runTimeParameters": [] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6248d65532][OT2_P300M_P20S_TC_HS_TM_2_15_SmokeTestV3].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0c4ae179bb][OT2_S_v2_15_P300M_P20S_HS_TC_TM_SmokeTestV3].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6248d65532][OT2_P300M_P20S_TC_HS_TM_2_15_SmokeTestV3].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0c4ae179bb][OT2_S_v2_15_P300M_P20S_HS_TC_TM_SmokeTestV3].json index 0fa87b61d1f..af14e1c5793 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6248d65532][OT2_P300M_P20S_TC_HS_TM_2_15_SmokeTestV3].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0c4ae179bb][OT2_S_v2_15_P300M_P20S_HS_TC_TM_SmokeTestV3].json @@ -15295,7 +15295,7 @@ "errors": [], "files": [ { - "name": "OT2_P300M_P20S_TC_HS_TM_2_15_SmokeTestV3.py", + "name": "OT2_S_v2_15_P300M_P20S_HS_TC_TM_SmokeTestV3.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1312a4eb81][Flex_P100_96_HS_TM_2_15_Quick_Zymo_RNA_Bacteria].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[10d250f82a][Flex_S_v2_15_P1000_96_GRIP_HS_TM_QuickZymoMagbeadRNAExtraction].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1312a4eb81][Flex_P100_96_HS_TM_2_15_Quick_Zymo_RNA_Bacteria].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[10d250f82a][Flex_S_v2_15_P1000_96_GRIP_HS_TM_QuickZymoMagbeadRNAExtraction].json index 5ee46e4e231..6c84830df87 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1312a4eb81][Flex_P100_96_HS_TM_2_15_Quick_Zymo_RNA_Bacteria].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[10d250f82a][Flex_S_v2_15_P1000_96_GRIP_HS_TM_QuickZymoMagbeadRNAExtraction].json @@ -13216,7 +13216,7 @@ ], "files": [ { - "name": "Flex_P100_96_HS_TM_2_15_Quick_Zymo_RNA_Bacteria.py", + "name": "Flex_S_v2_15_P1000_96_GRIP_HS_TM_QuickZymoMagbeadRNAExtraction.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[7ea2fdcec4][Flex_P1000MLeft_P50MRight_HS_MM_TC_TM_2_15_ABR3_Illumina_DNA_Enrichment].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[12a2a22254][Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAEnrichment].json similarity index 98% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[7ea2fdcec4][Flex_P1000MLeft_P50MRight_HS_MM_TC_TM_2_15_ABR3_Illumina_DNA_Enrichment].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[12a2a22254][Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAEnrichment].json index bcdd4fb2a95..205a09ef18e 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[7ea2fdcec4][Flex_P1000MLeft_P50MRight_HS_MM_TC_TM_2_15_ABR3_Illumina_DNA_Enrichment].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[12a2a22254][Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAEnrichment].json @@ -9555,7 +9555,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 50.0, "wellLocation": { "offset": { @@ -9581,7 +9581,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 50.0, "wellLocation": { "offset": { @@ -9597,7 +9597,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 50.0 }, @@ -9667,7 +9667,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 10.0, "wellLocation": { "offset": { @@ -9693,7 +9693,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 10.0, "wellLocation": { "offset": { @@ -9709,7 +9709,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 10.0 }, @@ -9779,7 +9779,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -9805,7 +9805,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -9821,7 +9821,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 10.0 }, @@ -9846,7 +9846,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -9855,7 +9855,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 90.0, "wellLocation": { "offset": { @@ -9871,7 +9871,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 90.0 }, @@ -9881,7 +9881,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 90.0, "wellLocation": { "offset": { @@ -9897,7 +9897,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 90.0 }, @@ -9991,7 +9991,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 121.0, "wellLocation": { "offset": { @@ -10017,7 +10017,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 121.0, "wellLocation": { "offset": { @@ -10033,7 +10033,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 121.0 }, @@ -10043,7 +10043,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 121.0, "wellLocation": { "offset": { @@ -10069,7 +10069,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 121.0, "wellLocation": { "offset": { @@ -10085,7 +10085,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 121.0 }, @@ -10095,7 +10095,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 121.0, "wellLocation": { "offset": { @@ -10121,7 +10121,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 121.0, "wellLocation": { "offset": { @@ -10137,7 +10137,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 121.0 }, @@ -10147,7 +10147,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 121.0, "wellLocation": { "offset": { @@ -10173,7 +10173,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 121.0, "wellLocation": { "offset": { @@ -10189,7 +10189,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 121.0 }, @@ -10274,7 +10274,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 } }, "status": "succeeded" @@ -10283,7 +10283,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 101.0, "wellLocation": { "offset": { @@ -10299,7 +10299,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 }, "volume": 101.0 }, @@ -10309,7 +10309,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 101.0, "wellLocation": { "offset": { @@ -10325,7 +10325,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 101.0 }, @@ -10402,7 +10402,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -10428,7 +10428,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -10454,7 +10454,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -10480,7 +10480,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -10506,7 +10506,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -10532,7 +10532,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -10558,7 +10558,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -10584,7 +10584,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -10610,7 +10610,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -10636,7 +10636,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -10662,7 +10662,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -10688,7 +10688,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -10714,7 +10714,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -10740,7 +10740,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -10766,7 +10766,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -10792,7 +10792,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -10808,7 +10808,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 125.0 }, @@ -10833,7 +10833,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -10842,7 +10842,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -10858,7 +10858,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -10883,7 +10883,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -10892,7 +10892,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -10908,7 +10908,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -10918,7 +10918,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -10934,7 +10934,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -10959,7 +10959,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -10968,7 +10968,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -10984,7 +10984,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -10994,7 +10994,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -11010,7 +11010,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -11035,7 +11035,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -11044,7 +11044,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -11060,7 +11060,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -11070,7 +11070,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -11086,7 +11086,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -11111,7 +11111,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -11120,7 +11120,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -11136,7 +11136,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -11146,7 +11146,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -11408,7 +11408,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -11434,7 +11434,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -11460,7 +11460,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -11486,7 +11486,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -11545,7 +11545,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -11569,7 +11569,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11701,7 +11701,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -11717,7 +11717,7 @@ "position": { "x": 57.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 200.0 }, @@ -11727,7 +11727,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -11743,7 +11743,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -11916,7 +11916,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -11975,7 +11975,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -12025,7 +12025,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -12060,7 +12060,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -12084,7 +12084,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -12206,7 +12206,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -12222,7 +12222,7 @@ "position": { "x": 66.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 200.0 }, @@ -12232,7 +12232,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -12248,7 +12248,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -12421,7 +12421,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -12480,7 +12480,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -12530,7 +12530,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -12565,7 +12565,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -12589,7 +12589,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -12711,7 +12711,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -12727,7 +12727,7 @@ "position": { "x": 75.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 200.0 }, @@ -12737,7 +12737,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -12753,7 +12753,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -12926,7 +12926,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -12985,7 +12985,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -13035,7 +13035,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -13070,7 +13070,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -13094,7 +13094,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -13216,7 +13216,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -13232,7 +13232,7 @@ "position": { "x": 84.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 200.0 }, @@ -13242,7 +13242,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -13258,7 +13258,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -13361,7 +13361,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.200000000000003 + "z": 22.2 } }, "status": "succeeded" @@ -13370,7 +13370,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -13386,7 +13386,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.200000000000003 + "z": 22.2 }, "volume": 200.0 }, @@ -13396,7 +13396,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -13412,7 +13412,7 @@ "position": { "x": 41.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -13551,7 +13551,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -13610,7 +13610,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -13660,7 +13660,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -13695,7 +13695,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -13719,7 +13719,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -13829,7 +13829,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 50.0, "wellLocation": { "offset": { @@ -13855,7 +13855,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 50.0, "wellLocation": { "offset": { @@ -13890,7 +13890,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 57.0, "wellLocation": { "offset": { "x": 0.0, @@ -14052,7 +14052,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 23.0, "wellLocation": { "offset": { @@ -14078,7 +14078,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 23.0, "wellLocation": { "offset": { @@ -14294,7 +14294,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 22.0, "wellLocation": { "offset": { @@ -14320,7 +14320,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 22.0, "wellLocation": { "offset": { @@ -14336,7 +14336,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 22.0 }, @@ -14406,7 +14406,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 4.0, "wellLocation": { "offset": { @@ -14432,7 +14432,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 4.0, "wellLocation": { "offset": { @@ -14448,7 +14448,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 4.0 }, @@ -14473,7 +14473,7 @@ "position": { "x": 84.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -14482,7 +14482,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -14498,7 +14498,7 @@ "position": { "x": 84.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -14508,7 +14508,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -14524,7 +14524,7 @@ "position": { "x": 84.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -14624,7 +14624,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 5.0, "wellLocation": { "offset": { @@ -14650,7 +14650,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 5.0, "wellLocation": { "offset": { @@ -14666,7 +14666,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 5.0 }, @@ -14736,7 +14736,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -14762,7 +14762,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -14778,7 +14778,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -14803,7 +14803,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -14812,7 +14812,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 45.0, "wellLocation": { "offset": { @@ -14828,7 +14828,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 45.0 }, @@ -14838,7 +14838,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 45.0, "wellLocation": { "offset": { @@ -14854,7 +14854,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 45.0 }, @@ -15012,7 +15012,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 } }, "status": "succeeded" @@ -15021,7 +15021,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 46.0, "wellLocation": { "offset": { @@ -15037,7 +15037,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 }, "volume": 46.0 }, @@ -15047,7 +15047,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 46.0, "wellLocation": { "offset": { @@ -15063,7 +15063,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 46.0 }, @@ -15133,7 +15133,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.5, "wellLocation": { "offset": { @@ -15159,7 +15159,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.5, "wellLocation": { "offset": { @@ -15185,7 +15185,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 40.5, "wellLocation": { "offset": { @@ -15211,7 +15211,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 40.5, "wellLocation": { "offset": { @@ -15227,7 +15227,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 40.5 }, @@ -15252,7 +15252,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -15261,7 +15261,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -15277,7 +15277,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 60.0 }, @@ -15302,7 +15302,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -15311,7 +15311,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -15327,7 +15327,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -15337,7 +15337,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -15353,7 +15353,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -15378,7 +15378,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -15387,7 +15387,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { @@ -15403,7 +15403,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 30.0 }, @@ -15413,7 +15413,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -15429,7 +15429,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 60.0 }, @@ -15454,7 +15454,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -15463,7 +15463,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -15479,7 +15479,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -15489,7 +15489,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -15505,7 +15505,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -15530,7 +15530,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -15539,7 +15539,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { @@ -15555,7 +15555,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 30.0 }, @@ -15565,7 +15565,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -15808,7 +15808,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -15867,7 +15867,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -15917,7 +15917,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -15952,7 +15952,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -16084,7 +16084,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -16206,7 +16206,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -16241,7 +16241,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -16421,7 +16421,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -16480,7 +16480,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -16530,7 +16530,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -16565,7 +16565,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -16697,7 +16697,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -16819,7 +16819,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -16854,7 +16854,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -17034,7 +17034,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -17093,7 +17093,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -17143,7 +17143,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -17178,7 +17178,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -17334,7 +17334,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -17360,7 +17360,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.0, "wellLocation": { "offset": { @@ -17395,7 +17395,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -17563,7 +17563,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -17613,7 +17613,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -17654,7 +17654,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -17663,7 +17663,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -17679,7 +17679,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -17713,7 +17713,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -17754,7 +17754,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -17763,7 +17763,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -17779,7 +17779,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -17813,7 +17813,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -17854,7 +17854,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -17863,7 +17863,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -17879,7 +17879,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -17913,7 +17913,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -17954,7 +17954,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -17963,7 +17963,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -17979,7 +17979,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -17989,7 +17989,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -18005,7 +18005,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -18015,7 +18015,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -18258,7 +18258,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 31.0, "wellLocation": { "offset": { @@ -18284,7 +18284,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -18341,7 +18341,7 @@ "errors": [], "files": [ { - "name": "Flex_P1000MLeft_P50MRight_HS_MM_TC_TM_2_15_ABR3_Illumina_DNA_Enrichment.py", + "name": "Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAEnrichment.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[52a42597a5][OT2_P300M_P20S_MM_HS_TD_TC_6_1_AllMods_Error].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[134037b2aa][OT2_X_v6_P300M_P20S_HS_MM_TM_TC_AllMods].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[52a42597a5][OT2_P300M_P20S_MM_HS_TD_TC_6_1_AllMods_Error].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[134037b2aa][OT2_X_v6_P300M_P20S_HS_MM_TM_TC_AllMods].json index b36a44a5457..a55bcdcad04 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[52a42597a5][OT2_P300M_P20S_MM_HS_TD_TC_6_1_AllMods_Error].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[134037b2aa][OT2_X_v6_P300M_P20S_HS_MM_TM_TC_AllMods].json @@ -7297,7 +7297,7 @@ ], "files": [ { - "name": "OT2_P300M_P20S_MM_HS_TD_TC_6_1_AllMods_Error.json", + "name": "OT2_X_v6_P300M_P20S_HS_MM_TM_TC_AllMods.json", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[37c9086bf4][Flex_P1000MLeft_P50MRight_HS_MM_TC_TM_2_15_ABR3_Illumina_DNA_Enrichment_v4].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1960aa7a4c][Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAEnrichmentv4].json similarity index 96% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[37c9086bf4][Flex_P1000MLeft_P50MRight_HS_MM_TC_TM_2_15_ABR3_Illumina_DNA_Enrichment_v4].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1960aa7a4c][Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAEnrichmentv4].json index 58867a05b3f..28e91a90e8e 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[37c9086bf4][Flex_P1000MLeft_P50MRight_HS_MM_TC_TM_2_15_ABR3_Illumina_DNA_Enrichment_v4].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1960aa7a4c][Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAEnrichmentv4].json @@ -11809,7 +11809,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 } }, "status": "succeeded" @@ -11818,7 +11818,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 101.0, "wellLocation": { "offset": { @@ -11834,7 +11834,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 }, "volume": 101.0 }, @@ -11844,7 +11844,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 101.0, "wellLocation": { "offset": { @@ -11860,7 +11860,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 101.0 }, @@ -11935,7 +11935,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 } }, "status": "succeeded" @@ -11944,7 +11944,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 101.0, "wellLocation": { "offset": { @@ -11960,7 +11960,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 }, "volume": 101.0 }, @@ -11970,7 +11970,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 101.0, "wellLocation": { "offset": { @@ -11986,7 +11986,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 101.0 }, @@ -12061,7 +12061,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 } }, "status": "succeeded" @@ -12070,7 +12070,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 101.0, "wellLocation": { "offset": { @@ -12086,7 +12086,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 }, "volume": 101.0 }, @@ -12096,7 +12096,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 101.0, "wellLocation": { "offset": { @@ -12112,7 +12112,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 101.0 }, @@ -12189,7 +12189,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -12215,7 +12215,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -12241,7 +12241,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -12267,7 +12267,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -12293,7 +12293,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -12319,7 +12319,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -12335,7 +12335,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 125.0 }, @@ -12360,7 +12360,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -12369,7 +12369,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -12385,7 +12385,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -12410,7 +12410,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -12419,7 +12419,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -12435,7 +12435,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -12445,7 +12445,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -12461,7 +12461,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -12486,7 +12486,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -12495,7 +12495,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -12511,7 +12511,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -12521,7 +12521,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -12537,7 +12537,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -12562,7 +12562,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -12571,7 +12571,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -12587,7 +12587,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -12597,7 +12597,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -12613,7 +12613,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -12638,7 +12638,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -12647,7 +12647,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -12663,7 +12663,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -12673,7 +12673,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -12819,7 +12819,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -12845,7 +12845,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -12871,7 +12871,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -12897,7 +12897,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -12923,7 +12923,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -12949,7 +12949,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -12965,7 +12965,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 125.0 }, @@ -12990,7 +12990,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -12999,7 +12999,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -13015,7 +13015,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -13040,7 +13040,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -13049,7 +13049,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -13065,7 +13065,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -13075,7 +13075,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -13091,7 +13091,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -13116,7 +13116,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -13125,7 +13125,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -13141,7 +13141,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -13151,7 +13151,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -13167,7 +13167,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -13192,7 +13192,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -13201,7 +13201,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -13217,7 +13217,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -13227,7 +13227,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -13243,7 +13243,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -13268,7 +13268,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -13277,7 +13277,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -13293,7 +13293,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -13303,7 +13303,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -13449,7 +13449,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -13475,7 +13475,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -13501,7 +13501,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -13527,7 +13527,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -13553,7 +13553,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -13579,7 +13579,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -13595,7 +13595,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 125.0 }, @@ -13620,7 +13620,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -13629,7 +13629,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -13645,7 +13645,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -13670,7 +13670,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -13679,7 +13679,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -13695,7 +13695,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -13705,7 +13705,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -13721,7 +13721,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -13746,7 +13746,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -13755,7 +13755,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -13771,7 +13771,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -13781,7 +13781,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -13797,7 +13797,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -13822,7 +13822,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -13831,7 +13831,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -13847,7 +13847,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -13857,7 +13857,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -13873,7 +13873,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -13898,7 +13898,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -13907,7 +13907,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -13923,7 +13923,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -13933,7 +13933,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -14215,7 +14215,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -14241,7 +14241,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -14291,7 +14291,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -14317,7 +14317,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -14376,7 +14376,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -14400,7 +14400,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -14500,7 +14500,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -14526,7 +14526,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -14576,7 +14576,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -14602,7 +14602,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -14661,7 +14661,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -14685,7 +14685,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -14785,7 +14785,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -14811,7 +14811,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -14861,7 +14861,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -14887,7 +14887,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -14946,7 +14946,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -14970,7 +14970,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -15102,7 +15102,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -15118,7 +15118,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -15128,7 +15128,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -15144,7 +15144,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -15204,7 +15204,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -15220,7 +15220,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -15230,7 +15230,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -15246,7 +15246,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -15306,7 +15306,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -15322,7 +15322,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -15332,7 +15332,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -15348,7 +15348,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -15514,7 +15514,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -15573,7 +15573,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -15623,7 +15623,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -15658,7 +15658,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -15682,7 +15682,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -15782,7 +15782,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -15841,7 +15841,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -15891,7 +15891,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -15926,7 +15926,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -15950,7 +15950,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -16050,7 +16050,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -16109,7 +16109,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -16159,7 +16159,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -16194,7 +16194,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -16218,7 +16218,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -16340,7 +16340,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -16356,7 +16356,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -16366,7 +16366,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -16382,7 +16382,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -16442,7 +16442,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -16458,7 +16458,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -16468,7 +16468,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -16484,7 +16484,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -16544,7 +16544,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -16560,7 +16560,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -16570,7 +16570,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -16586,7 +16586,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -16752,7 +16752,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -16811,7 +16811,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -16861,7 +16861,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -16896,7 +16896,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -16920,7 +16920,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -17020,7 +17020,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -17079,7 +17079,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -17129,7 +17129,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -17164,7 +17164,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -17188,7 +17188,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -17288,7 +17288,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -17347,7 +17347,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -17397,7 +17397,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -17432,7 +17432,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -17456,7 +17456,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -17578,7 +17578,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -17594,7 +17594,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -17604,7 +17604,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -17620,7 +17620,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -17680,7 +17680,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -17696,7 +17696,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -17706,7 +17706,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -17722,7 +17722,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -17782,7 +17782,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -17798,7 +17798,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -17808,7 +17808,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -17824,7 +17824,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -17990,7 +17990,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -18049,7 +18049,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -18099,7 +18099,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18134,7 +18134,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -18158,7 +18158,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -18258,7 +18258,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -18317,7 +18317,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -18367,7 +18367,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18402,7 +18402,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -18426,7 +18426,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -18526,7 +18526,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -18585,7 +18585,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -18635,7 +18635,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18670,7 +18670,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -18694,7 +18694,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -18816,7 +18816,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18832,7 +18832,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -18842,7 +18842,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18858,7 +18858,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -18918,7 +18918,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18934,7 +18934,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -18944,7 +18944,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18960,7 +18960,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -19020,7 +19020,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -19036,7 +19036,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -19046,7 +19046,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -19062,7 +19062,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -19165,7 +19165,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.200000000000003 + "z": 22.2 } }, "status": "succeeded" @@ -19174,7 +19174,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -19190,7 +19190,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.200000000000003 + "z": 22.2 }, "volume": 200.0 }, @@ -19200,7 +19200,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -19216,7 +19216,7 @@ "position": { "x": 41.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -19291,7 +19291,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.200000000000003 + "z": 22.2 } }, "status": "succeeded" @@ -19300,7 +19300,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -19316,7 +19316,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.200000000000003 + "z": 22.2 }, "volume": 200.0 }, @@ -19326,7 +19326,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -19342,7 +19342,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -19417,7 +19417,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.200000000000003 + "z": 22.2 } }, "status": "succeeded" @@ -19426,7 +19426,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -19442,7 +19442,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.200000000000003 + "z": 22.2 }, "volume": 200.0 }, @@ -19452,7 +19452,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -19468,7 +19468,7 @@ "position": { "x": 59.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -19600,7 +19600,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -19659,7 +19659,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -19709,7 +19709,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -19744,7 +19744,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -19768,7 +19768,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -19868,7 +19868,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -19927,7 +19927,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -19977,7 +19977,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -20012,7 +20012,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -20036,7 +20036,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -20136,7 +20136,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -20195,7 +20195,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -20245,7 +20245,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -20280,7 +20280,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -20304,7 +20304,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -20414,7 +20414,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 50.0, "wellLocation": { "offset": { @@ -20440,7 +20440,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 50.0, "wellLocation": { "offset": { @@ -20475,7 +20475,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 57.0, "wellLocation": { "offset": { "x": 0.0, @@ -20621,7 +20621,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 50.0, "wellLocation": { "offset": { @@ -20647,7 +20647,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 50.0, "wellLocation": { "offset": { @@ -20682,7 +20682,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 57.0, "wellLocation": { "offset": { "x": 0.0, @@ -20828,7 +20828,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 50.0, "wellLocation": { "offset": { @@ -20854,7 +20854,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 50.0, "wellLocation": { "offset": { @@ -20889,7 +20889,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 57.0, "wellLocation": { "offset": { "x": 0.0, @@ -21051,7 +21051,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 23.0, "wellLocation": { "offset": { @@ -21077,7 +21077,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 23.0, "wellLocation": { "offset": { @@ -21153,7 +21153,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 23.0, "wellLocation": { "offset": { @@ -21179,7 +21179,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 23.0, "wellLocation": { "offset": { @@ -21255,7 +21255,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 23.0, "wellLocation": { "offset": { @@ -21281,7 +21281,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 23.0, "wellLocation": { "offset": { @@ -21499,7 +21499,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 22.0, "wellLocation": { "offset": { @@ -21525,7 +21525,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 22.0, "wellLocation": { "offset": { @@ -21541,7 +21541,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 22.0 }, @@ -21625,7 +21625,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 22.0, "wellLocation": { "offset": { @@ -21651,7 +21651,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 22.0, "wellLocation": { "offset": { @@ -21667,7 +21667,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 22.0 }, @@ -21751,7 +21751,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 22.0, "wellLocation": { "offset": { @@ -21777,7 +21777,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 22.0, "wellLocation": { "offset": { @@ -21793,7 +21793,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 22.0 }, @@ -21863,7 +21863,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 4.0, "wellLocation": { "offset": { @@ -21889,7 +21889,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 4.0, "wellLocation": { "offset": { @@ -21905,7 +21905,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 4.0 }, @@ -21930,7 +21930,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -21939,7 +21939,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -21955,7 +21955,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -21965,7 +21965,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -21981,7 +21981,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -22041,7 +22041,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 4.0, "wellLocation": { "offset": { @@ -22067,7 +22067,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 4.0, "wellLocation": { "offset": { @@ -22083,7 +22083,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 4.0 }, @@ -22108,7 +22108,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -22117,7 +22117,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -22133,7 +22133,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -22143,7 +22143,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -22159,7 +22159,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -22219,7 +22219,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 4.0, "wellLocation": { "offset": { @@ -22245,7 +22245,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 4.0, "wellLocation": { "offset": { @@ -22261,7 +22261,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 4.0 }, @@ -22286,7 +22286,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -22295,7 +22295,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -22311,7 +22311,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -22321,7 +22321,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -22337,7 +22337,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -22437,7 +22437,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 5.0, "wellLocation": { "offset": { @@ -22463,7 +22463,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 5.0, "wellLocation": { "offset": { @@ -22479,7 +22479,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 5.0 }, @@ -22539,7 +22539,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 5.0, "wellLocation": { "offset": { @@ -22565,7 +22565,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 5.0, "wellLocation": { "offset": { @@ -22581,7 +22581,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 5.0 }, @@ -22641,7 +22641,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 5.0, "wellLocation": { "offset": { @@ -22667,7 +22667,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 5.0, "wellLocation": { "offset": { @@ -22683,7 +22683,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 5.0 }, @@ -22753,7 +22753,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -22779,7 +22779,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -22795,7 +22795,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -22820,7 +22820,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -22829,7 +22829,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 45.0, "wellLocation": { "offset": { @@ -22845,7 +22845,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 45.0 }, @@ -22855,7 +22855,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 45.0, "wellLocation": { "offset": { @@ -22871,7 +22871,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 45.0 }, @@ -22931,7 +22931,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -22957,7 +22957,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -22973,7 +22973,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -22998,7 +22998,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -23007,7 +23007,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 45.0, "wellLocation": { "offset": { @@ -23023,7 +23023,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 45.0 }, @@ -23033,7 +23033,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 45.0, "wellLocation": { "offset": { @@ -23049,7 +23049,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 45.0 }, @@ -23109,7 +23109,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -23135,7 +23135,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -23151,7 +23151,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -23176,7 +23176,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -23185,7 +23185,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 45.0, "wellLocation": { "offset": { @@ -23201,7 +23201,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 45.0 }, @@ -23211,7 +23211,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 45.0, "wellLocation": { "offset": { @@ -23227,7 +23227,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 45.0 }, @@ -23378,7 +23378,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 } }, "status": "succeeded" @@ -23387,7 +23387,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 46.0, "wellLocation": { "offset": { @@ -23403,7 +23403,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 }, "volume": 46.0 }, @@ -23413,7 +23413,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 46.0, "wellLocation": { "offset": { @@ -23429,7 +23429,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 46.0 }, @@ -23504,7 +23504,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 } }, "status": "succeeded" @@ -23513,7 +23513,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 46.0, "wellLocation": { "offset": { @@ -23529,7 +23529,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 }, "volume": 46.0 }, @@ -23539,7 +23539,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 46.0, "wellLocation": { "offset": { @@ -23555,7 +23555,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 46.0 }, @@ -23630,7 +23630,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 } }, "status": "succeeded" @@ -23639,7 +23639,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 46.0, "wellLocation": { "offset": { @@ -23655,7 +23655,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 }, "volume": 46.0 }, @@ -23665,7 +23665,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 46.0, "wellLocation": { "offset": { @@ -23681,7 +23681,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 46.0 }, @@ -23751,7 +23751,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.5, "wellLocation": { "offset": { @@ -23777,7 +23777,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.5, "wellLocation": { "offset": { @@ -23803,7 +23803,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 40.5, "wellLocation": { "offset": { @@ -23829,7 +23829,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 40.5, "wellLocation": { "offset": { @@ -23845,7 +23845,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 40.5 }, @@ -23870,7 +23870,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -23879,7 +23879,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -23895,7 +23895,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 60.0 }, @@ -23920,7 +23920,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -23929,7 +23929,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -23945,7 +23945,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -23955,7 +23955,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -23971,7 +23971,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -23996,7 +23996,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -24005,7 +24005,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { @@ -24021,7 +24021,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 30.0 }, @@ -24031,7 +24031,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -24047,7 +24047,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 60.0 }, @@ -24072,7 +24072,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -24081,7 +24081,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -24097,7 +24097,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -24107,7 +24107,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -24123,7 +24123,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -24148,7 +24148,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -24157,7 +24157,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { @@ -24173,7 +24173,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 30.0 }, @@ -24183,7 +24183,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -24329,7 +24329,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.5, "wellLocation": { "offset": { @@ -24355,7 +24355,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.5, "wellLocation": { "offset": { @@ -24381,7 +24381,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 40.5, "wellLocation": { "offset": { @@ -24407,7 +24407,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 40.5, "wellLocation": { "offset": { @@ -24423,7 +24423,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 40.5 }, @@ -24448,7 +24448,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -24457,7 +24457,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -24473,7 +24473,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 60.0 }, @@ -24498,7 +24498,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -24507,7 +24507,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -24523,7 +24523,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -24533,7 +24533,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -24549,7 +24549,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -24574,7 +24574,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -24583,7 +24583,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { @@ -24599,7 +24599,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 30.0 }, @@ -24609,7 +24609,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -24625,7 +24625,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 60.0 }, @@ -24650,7 +24650,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -24659,7 +24659,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -24675,7 +24675,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -24685,7 +24685,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -24701,7 +24701,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -24726,7 +24726,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -24735,7 +24735,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { @@ -24751,7 +24751,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 30.0 }, @@ -24761,7 +24761,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -24907,7 +24907,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.5, "wellLocation": { "offset": { @@ -24933,7 +24933,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.5, "wellLocation": { "offset": { @@ -24959,7 +24959,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 40.5, "wellLocation": { "offset": { @@ -24985,7 +24985,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 40.5, "wellLocation": { "offset": { @@ -25001,7 +25001,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 40.5 }, @@ -25026,7 +25026,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -25035,7 +25035,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -25051,7 +25051,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 60.0 }, @@ -25076,7 +25076,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -25085,7 +25085,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -25101,7 +25101,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -25111,7 +25111,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -25127,7 +25127,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -25152,7 +25152,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -25161,7 +25161,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { @@ -25177,7 +25177,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 30.0 }, @@ -25187,7 +25187,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -25203,7 +25203,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 60.0 }, @@ -25228,7 +25228,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -25237,7 +25237,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -25253,7 +25253,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -25263,7 +25263,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -25279,7 +25279,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -25304,7 +25304,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -25313,7 +25313,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { @@ -25329,7 +25329,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 30.0 }, @@ -25339,7 +25339,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -25584,7 +25584,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -25643,7 +25643,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -25693,7 +25693,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -25728,7 +25728,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -25874,7 +25874,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -25933,7 +25933,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -25983,7 +25983,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -26018,7 +26018,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -26164,7 +26164,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -26223,7 +26223,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -26273,7 +26273,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -26308,7 +26308,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -26440,7 +26440,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -26562,7 +26562,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -26597,7 +26597,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -26743,7 +26743,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -26865,7 +26865,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -26900,7 +26900,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -27046,7 +27046,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -27168,7 +27168,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -27203,7 +27203,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -27383,7 +27383,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -27442,7 +27442,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -27492,7 +27492,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -27527,7 +27527,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -27673,7 +27673,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -27732,7 +27732,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -27782,7 +27782,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -27817,7 +27817,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -27963,7 +27963,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -28022,7 +28022,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -28072,7 +28072,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -28107,7 +28107,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -28239,7 +28239,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -28361,7 +28361,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -28396,7 +28396,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -28542,7 +28542,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -28664,7 +28664,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -28699,7 +28699,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -28845,7 +28845,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -28967,7 +28967,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -29002,7 +29002,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -29182,7 +29182,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -29241,7 +29241,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -29291,7 +29291,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -29326,7 +29326,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -29472,7 +29472,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -29531,7 +29531,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -29581,7 +29581,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -29616,7 +29616,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -29762,7 +29762,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -29821,7 +29821,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -29871,7 +29871,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -29906,7 +29906,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -30062,7 +30062,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -30088,7 +30088,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.0, "wellLocation": { "offset": { @@ -30123,7 +30123,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -30269,7 +30269,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -30295,7 +30295,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.0, "wellLocation": { "offset": { @@ -30330,7 +30330,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -30476,7 +30476,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -30502,7 +30502,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.0, "wellLocation": { "offset": { @@ -30537,7 +30537,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -30705,7 +30705,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -30755,7 +30755,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -30796,7 +30796,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -30805,7 +30805,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -30821,7 +30821,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -30855,7 +30855,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -30896,7 +30896,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -30905,7 +30905,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -30921,7 +30921,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -30955,7 +30955,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -30996,7 +30996,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -31005,7 +31005,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -31021,7 +31021,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -31055,7 +31055,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -31096,7 +31096,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -31105,7 +31105,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -31121,7 +31121,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -31131,7 +31131,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -31147,7 +31147,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -31157,7 +31157,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -31303,7 +31303,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -31353,7 +31353,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -31394,7 +31394,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -31403,7 +31403,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -31419,7 +31419,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -31453,7 +31453,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -31494,7 +31494,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -31503,7 +31503,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -31519,7 +31519,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -31553,7 +31553,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -31594,7 +31594,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -31603,7 +31603,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -31619,7 +31619,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -31653,7 +31653,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -31694,7 +31694,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -31703,7 +31703,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -31719,7 +31719,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -31729,7 +31729,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -31745,7 +31745,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -31755,7 +31755,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -31901,7 +31901,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -31951,7 +31951,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -31992,7 +31992,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -32001,7 +32001,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -32017,7 +32017,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -32051,7 +32051,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -32092,7 +32092,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -32101,7 +32101,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -32117,7 +32117,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -32151,7 +32151,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -32192,7 +32192,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -32201,7 +32201,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -32217,7 +32217,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -32251,7 +32251,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -32292,7 +32292,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -32301,7 +32301,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -32317,7 +32317,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -32327,7 +32327,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -32343,7 +32343,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -32353,7 +32353,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -32571,7 +32571,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 31.0, "wellLocation": { "offset": { @@ -32597,7 +32597,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -32613,7 +32613,7 @@ "position": { "x": 48.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 31.0 }, @@ -32697,7 +32697,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 31.0, "wellLocation": { "offset": { @@ -32723,7 +32723,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -32739,7 +32739,7 @@ "position": { "x": 57.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 31.0 }, @@ -32823,7 +32823,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 31.0, "wellLocation": { "offset": { @@ -32849,7 +32849,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -32865,7 +32865,7 @@ "position": { "x": 66.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 31.0 }, @@ -32991,7 +32991,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -33017,7 +33017,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -33043,7 +33043,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -33069,7 +33069,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -33095,7 +33095,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -33121,7 +33121,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -33147,7 +33147,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -33173,7 +33173,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -33199,7 +33199,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -33225,7 +33225,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -33251,7 +33251,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -33277,7 +33277,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -33303,7 +33303,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -33329,7 +33329,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -33355,7 +33355,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -33381,7 +33381,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -33407,7 +33407,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -33433,7 +33433,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -33459,7 +33459,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -33485,7 +33485,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -33501,7 +33501,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -33511,7 +33511,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -33537,7 +33537,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -33553,7 +33553,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -33563,7 +33563,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -33589,7 +33589,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -33605,7 +33605,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -33615,7 +33615,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -33641,7 +33641,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -33657,7 +33657,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -33667,7 +33667,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -33693,7 +33693,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -33709,7 +33709,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -33719,7 +33719,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -33745,7 +33745,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -33761,7 +33761,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -33771,7 +33771,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -33797,7 +33797,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -33813,7 +33813,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -33823,7 +33823,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -33849,7 +33849,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -33865,7 +33865,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -33875,7 +33875,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -33901,7 +33901,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -33917,7 +33917,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -33927,7 +33927,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -33953,7 +33953,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -33969,7 +33969,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -33979,7 +33979,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34005,7 +34005,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34021,7 +34021,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -34031,7 +34031,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34057,7 +34057,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34073,7 +34073,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -34083,7 +34083,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34109,7 +34109,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34125,7 +34125,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -34135,7 +34135,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34161,7 +34161,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34177,7 +34177,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -34187,7 +34187,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34213,7 +34213,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34229,7 +34229,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -34239,7 +34239,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34265,7 +34265,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34281,7 +34281,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -34291,7 +34291,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34317,7 +34317,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34333,7 +34333,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -34343,7 +34343,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34369,7 +34369,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34385,7 +34385,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -34395,7 +34395,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34421,7 +34421,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34437,7 +34437,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -34447,7 +34447,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34473,7 +34473,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34489,7 +34489,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -34499,7 +34499,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34525,7 +34525,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34541,7 +34541,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -34551,7 +34551,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34577,7 +34577,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34593,7 +34593,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -34603,7 +34603,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34629,7 +34629,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34645,7 +34645,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -34655,7 +34655,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34681,7 +34681,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34697,7 +34697,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -34707,7 +34707,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34733,7 +34733,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34749,7 +34749,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -34759,7 +34759,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34785,7 +34785,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34801,7 +34801,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -34811,7 +34811,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34837,7 +34837,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34853,7 +34853,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -34863,7 +34863,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34889,7 +34889,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34905,7 +34905,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -34915,7 +34915,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34941,7 +34941,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34957,7 +34957,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -34967,7 +34967,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -34993,7 +34993,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -35009,7 +35009,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -35019,7 +35019,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -35045,7 +35045,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -35061,7 +35061,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -35071,7 +35071,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -35097,7 +35097,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -35113,7 +35113,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -35123,7 +35123,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -35149,7 +35149,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -35165,7 +35165,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -35175,7 +35175,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -35201,7 +35201,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -35217,7 +35217,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -35227,7 +35227,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -35253,7 +35253,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -35269,7 +35269,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -35279,7 +35279,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -35305,7 +35305,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -35321,7 +35321,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -35331,7 +35331,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -35357,7 +35357,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -35383,7 +35383,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -35409,7 +35409,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -35435,7 +35435,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -35461,7 +35461,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -35487,7 +35487,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -35513,7 +35513,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -35539,7 +35539,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -35565,7 +35565,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -35591,7 +35591,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -35617,7 +35617,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -35643,7 +35643,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 121.5, "wellLocation": { "offset": { @@ -35669,7 +35669,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 121.5, "wellLocation": { "offset": { @@ -35695,7 +35695,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 121.5, "wellLocation": { "offset": { @@ -35721,7 +35721,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 121.5, "wellLocation": { "offset": { @@ -35747,7 +35747,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 121.5, "wellLocation": { "offset": { @@ -35773,7 +35773,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 121.5, "wellLocation": { "offset": { @@ -35799,7 +35799,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 75.0, "wellLocation": { "offset": { @@ -35825,7 +35825,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 75.0, "wellLocation": { "offset": { @@ -35851,7 +35851,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 120.0, "wellLocation": { "offset": { @@ -35877,7 +35877,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 120.0, "wellLocation": { "offset": { @@ -35953,7 +35953,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 12.0, "wellLocation": { "offset": { @@ -35979,7 +35979,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 12.0, "wellLocation": { "offset": { @@ -36005,7 +36005,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 15.0, "wellLocation": { "offset": { @@ -36031,7 +36031,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 15.0, "wellLocation": { "offset": { @@ -36057,7 +36057,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 32.0, "wellLocation": { "offset": { @@ -36073,7 +36073,7 @@ "position": { "x": 48.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 32.0 }, @@ -36083,7 +36083,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 32.0, "wellLocation": { "offset": { @@ -36109,7 +36109,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 32.0, "wellLocation": { "offset": { @@ -36125,7 +36125,7 @@ "position": { "x": 57.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 32.0 }, @@ -36135,7 +36135,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 32.0, "wellLocation": { "offset": { @@ -36161,7 +36161,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 32.0, "wellLocation": { "offset": { @@ -36177,7 +36177,7 @@ "position": { "x": 66.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 32.0 }, @@ -36187,7 +36187,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 32.0, "wellLocation": { "offset": { @@ -36213,7 +36213,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 30.0, "wellLocation": { "offset": { @@ -36239,7 +36239,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 30.0, "wellLocation": { "offset": { @@ -36255,7 +36255,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 30.0 }, @@ -36265,7 +36265,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 30.0, "wellLocation": { "offset": { @@ -36291,7 +36291,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 30.0, "wellLocation": { "offset": { @@ -36307,7 +36307,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 30.0 }, @@ -36317,7 +36317,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 30.0, "wellLocation": { "offset": { @@ -36343,7 +36343,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 30.0, "wellLocation": { "offset": { @@ -36359,7 +36359,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 30.0 }, @@ -36506,7 +36506,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 } }, "status": "succeeded" @@ -36515,7 +36515,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 101.0, "wellLocation": { "offset": { @@ -36531,7 +36531,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 }, "volume": 101.0 }, @@ -36541,7 +36541,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 101.0, "wellLocation": { "offset": { @@ -36557,7 +36557,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 101.0 }, @@ -36632,7 +36632,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 } }, "status": "succeeded" @@ -36641,7 +36641,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 101.0, "wellLocation": { "offset": { @@ -36657,7 +36657,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 }, "volume": 101.0 }, @@ -36667,7 +36667,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 101.0, "wellLocation": { "offset": { @@ -36683,7 +36683,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 101.0 }, @@ -36758,7 +36758,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 } }, "status": "succeeded" @@ -36767,7 +36767,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 101.0, "wellLocation": { "offset": { @@ -36783,7 +36783,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 }, "volume": 101.0 }, @@ -36793,7 +36793,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 101.0, "wellLocation": { "offset": { @@ -36809,7 +36809,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 101.0 }, @@ -36886,7 +36886,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -36912,7 +36912,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -36938,7 +36938,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -36964,7 +36964,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -36990,7 +36990,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -37016,7 +37016,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -37032,7 +37032,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 125.0 }, @@ -37057,7 +37057,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -37066,7 +37066,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -37082,7 +37082,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -37107,7 +37107,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -37116,7 +37116,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -37132,7 +37132,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -37142,7 +37142,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -37158,7 +37158,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -37183,7 +37183,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -37192,7 +37192,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -37208,7 +37208,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -37218,7 +37218,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -37234,7 +37234,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -37259,7 +37259,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -37268,7 +37268,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -37284,7 +37284,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -37294,7 +37294,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -37310,7 +37310,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -37335,7 +37335,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -37344,7 +37344,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -37360,7 +37360,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -37370,7 +37370,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -37516,7 +37516,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -37542,7 +37542,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -37568,7 +37568,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -37594,7 +37594,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -37620,7 +37620,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -37646,7 +37646,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -37662,7 +37662,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 125.0 }, @@ -37687,7 +37687,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -37696,7 +37696,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -37712,7 +37712,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -37737,7 +37737,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -37746,7 +37746,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -37762,7 +37762,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -37772,7 +37772,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -37788,7 +37788,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -37813,7 +37813,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -37822,7 +37822,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -37838,7 +37838,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -37848,7 +37848,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -37864,7 +37864,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -37889,7 +37889,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -37898,7 +37898,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -37914,7 +37914,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -37924,7 +37924,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -37940,7 +37940,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -37965,7 +37965,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -37974,7 +37974,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -37990,7 +37990,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -38000,7 +38000,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -38146,7 +38146,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -38172,7 +38172,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -38198,7 +38198,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -38224,7 +38224,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -38250,7 +38250,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -38276,7 +38276,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -38292,7 +38292,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 125.0 }, @@ -38317,7 +38317,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -38326,7 +38326,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -38342,7 +38342,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -38367,7 +38367,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -38376,7 +38376,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -38392,7 +38392,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -38402,7 +38402,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -38418,7 +38418,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -38443,7 +38443,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -38452,7 +38452,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -38468,7 +38468,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -38478,7 +38478,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -38494,7 +38494,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -38519,7 +38519,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -38528,7 +38528,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -38544,7 +38544,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -38554,7 +38554,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -38570,7 +38570,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -38595,7 +38595,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -38604,7 +38604,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -38620,7 +38620,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -38630,7 +38630,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -38912,7 +38912,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -38938,7 +38938,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -38988,7 +38988,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -39014,7 +39014,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -39073,7 +39073,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -39097,7 +39097,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -39197,7 +39197,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -39223,7 +39223,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -39273,7 +39273,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -39299,7 +39299,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -39358,7 +39358,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -39382,7 +39382,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -39482,7 +39482,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -39508,7 +39508,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -39558,7 +39558,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -39584,7 +39584,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -39643,7 +39643,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -39667,7 +39667,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -39799,7 +39799,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -39815,7 +39815,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -39825,7 +39825,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -39841,7 +39841,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -39901,7 +39901,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -39917,7 +39917,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -39927,7 +39927,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -39943,7 +39943,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -40003,7 +40003,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -40019,7 +40019,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -40029,7 +40029,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -40045,7 +40045,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -40211,7 +40211,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -40270,7 +40270,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -40320,7 +40320,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -40355,7 +40355,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -40379,7 +40379,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -40479,7 +40479,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -40538,7 +40538,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -40588,7 +40588,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -40623,7 +40623,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -40647,7 +40647,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -40747,7 +40747,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -40806,7 +40806,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -40856,7 +40856,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -40891,7 +40891,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -40915,7 +40915,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -41037,7 +41037,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -41053,7 +41053,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -41063,7 +41063,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -41079,7 +41079,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -41139,7 +41139,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -41155,7 +41155,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -41165,7 +41165,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -41181,7 +41181,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -41241,7 +41241,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -41257,7 +41257,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -41267,7 +41267,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -41283,7 +41283,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -41449,7 +41449,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -41508,7 +41508,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -41558,7 +41558,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -41593,7 +41593,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -41617,7 +41617,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -41717,7 +41717,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -41776,7 +41776,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -41826,7 +41826,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -41861,7 +41861,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -41885,7 +41885,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -41985,7 +41985,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -42044,7 +42044,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -42094,7 +42094,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -42129,7 +42129,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -42153,7 +42153,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -42275,7 +42275,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -42291,7 +42291,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -42301,7 +42301,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -42317,7 +42317,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -42377,7 +42377,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -42393,7 +42393,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -42403,7 +42403,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -42419,7 +42419,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -42479,7 +42479,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -42495,7 +42495,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -42505,7 +42505,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -42521,7 +42521,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -42687,7 +42687,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -42746,7 +42746,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -42796,7 +42796,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -42831,7 +42831,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -42855,7 +42855,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -42955,7 +42955,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -43014,7 +43014,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -43064,7 +43064,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -43099,7 +43099,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -43123,7 +43123,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -43223,7 +43223,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -43282,7 +43282,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -43332,7 +43332,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -43367,7 +43367,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -43391,7 +43391,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -43513,7 +43513,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -43529,7 +43529,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -43539,7 +43539,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -43555,7 +43555,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -43615,7 +43615,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -43631,7 +43631,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -43641,7 +43641,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -43657,7 +43657,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -43717,7 +43717,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -43733,7 +43733,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -43743,7 +43743,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -43759,7 +43759,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -43862,7 +43862,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.200000000000003 + "z": 22.2 } }, "status": "succeeded" @@ -43871,7 +43871,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -43887,7 +43887,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.200000000000003 + "z": 22.2 }, "volume": 200.0 }, @@ -43897,7 +43897,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -43913,7 +43913,7 @@ "position": { "x": 41.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -43988,7 +43988,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.200000000000003 + "z": 22.2 } }, "status": "succeeded" @@ -43997,7 +43997,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -44013,7 +44013,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.200000000000003 + "z": 22.2 }, "volume": 200.0 }, @@ -44023,7 +44023,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -44039,7 +44039,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -44114,7 +44114,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.200000000000003 + "z": 22.2 } }, "status": "succeeded" @@ -44123,7 +44123,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -44139,7 +44139,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.200000000000003 + "z": 22.2 }, "volume": 200.0 }, @@ -44149,7 +44149,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -44165,7 +44165,7 @@ "position": { "x": 59.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -44297,7 +44297,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -44356,7 +44356,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -44406,7 +44406,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -44441,7 +44441,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -44465,7 +44465,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -44565,7 +44565,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -44624,7 +44624,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -44674,7 +44674,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -44709,7 +44709,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -44733,7 +44733,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -44833,7 +44833,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -44892,7 +44892,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -44942,7 +44942,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -44977,7 +44977,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -45001,7 +45001,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -45111,7 +45111,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 50.0, "wellLocation": { "offset": { @@ -45137,7 +45137,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 50.0, "wellLocation": { "offset": { @@ -45172,7 +45172,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 57.0, "wellLocation": { "offset": { "x": 0.0, @@ -45318,7 +45318,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 50.0, "wellLocation": { "offset": { @@ -45344,7 +45344,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 50.0, "wellLocation": { "offset": { @@ -45379,7 +45379,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 57.0, "wellLocation": { "offset": { "x": 0.0, @@ -45525,7 +45525,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 50.0, "wellLocation": { "offset": { @@ -45551,7 +45551,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 50.0, "wellLocation": { "offset": { @@ -45586,7 +45586,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 57.0, "wellLocation": { "offset": { "x": 0.0, @@ -45748,7 +45748,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 23.0, "wellLocation": { "offset": { @@ -45774,7 +45774,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 23.0, "wellLocation": { "offset": { @@ -45850,7 +45850,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 23.0, "wellLocation": { "offset": { @@ -45876,7 +45876,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 23.0, "wellLocation": { "offset": { @@ -45952,7 +45952,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 23.0, "wellLocation": { "offset": { @@ -45978,7 +45978,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 23.0, "wellLocation": { "offset": { @@ -46196,7 +46196,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 22.0, "wellLocation": { "offset": { @@ -46222,7 +46222,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 22.0, "wellLocation": { "offset": { @@ -46238,7 +46238,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 22.0 }, @@ -46322,7 +46322,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 22.0, "wellLocation": { "offset": { @@ -46348,7 +46348,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 22.0, "wellLocation": { "offset": { @@ -46364,7 +46364,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 22.0 }, @@ -46448,7 +46448,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 22.0, "wellLocation": { "offset": { @@ -46474,7 +46474,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 22.0, "wellLocation": { "offset": { @@ -46490,7 +46490,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 22.0 }, @@ -46560,7 +46560,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 4.0, "wellLocation": { "offset": { @@ -46586,7 +46586,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 4.0, "wellLocation": { "offset": { @@ -46602,7 +46602,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 4.0 }, @@ -46627,7 +46627,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -46636,7 +46636,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -46652,7 +46652,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -46662,7 +46662,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -46678,7 +46678,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -46738,7 +46738,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 4.0, "wellLocation": { "offset": { @@ -46764,7 +46764,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 4.0, "wellLocation": { "offset": { @@ -46780,7 +46780,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 4.0 }, @@ -46805,7 +46805,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -46814,7 +46814,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -46830,7 +46830,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -46840,7 +46840,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -46856,7 +46856,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -46916,7 +46916,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 4.0, "wellLocation": { "offset": { @@ -46942,7 +46942,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 4.0, "wellLocation": { "offset": { @@ -46958,7 +46958,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 4.0 }, @@ -46983,7 +46983,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -46992,7 +46992,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -47008,7 +47008,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -47018,7 +47018,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -47034,7 +47034,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -47134,7 +47134,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 5.0, "wellLocation": { "offset": { @@ -47160,7 +47160,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 5.0, "wellLocation": { "offset": { @@ -47176,7 +47176,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 5.0 }, @@ -47236,7 +47236,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 5.0, "wellLocation": { "offset": { @@ -47262,7 +47262,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 5.0, "wellLocation": { "offset": { @@ -47278,7 +47278,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 5.0 }, @@ -47338,7 +47338,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 5.0, "wellLocation": { "offset": { @@ -47364,7 +47364,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 5.0, "wellLocation": { "offset": { @@ -47380,7 +47380,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 5.0 }, @@ -47450,7 +47450,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -47476,7 +47476,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -47492,7 +47492,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -47517,7 +47517,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -47526,7 +47526,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 45.0, "wellLocation": { "offset": { @@ -47542,7 +47542,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 45.0 }, @@ -47552,7 +47552,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 45.0, "wellLocation": { "offset": { @@ -47568,7 +47568,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 45.0 }, @@ -47628,7 +47628,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -47654,7 +47654,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -47670,7 +47670,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -47695,7 +47695,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -47704,7 +47704,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 45.0, "wellLocation": { "offset": { @@ -47720,7 +47720,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 45.0 }, @@ -47730,7 +47730,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 45.0, "wellLocation": { "offset": { @@ -47746,7 +47746,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 45.0 }, @@ -47806,7 +47806,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -47832,7 +47832,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -47848,7 +47848,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -47873,7 +47873,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -47882,7 +47882,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 45.0, "wellLocation": { "offset": { @@ -47898,7 +47898,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 45.0 }, @@ -47908,7 +47908,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 45.0, "wellLocation": { "offset": { @@ -47924,7 +47924,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 45.0 }, @@ -48075,7 +48075,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 } }, "status": "succeeded" @@ -48084,7 +48084,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 46.0, "wellLocation": { "offset": { @@ -48100,7 +48100,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 }, "volume": 46.0 }, @@ -48110,7 +48110,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 46.0, "wellLocation": { "offset": { @@ -48126,7 +48126,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 46.0 }, @@ -48201,7 +48201,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 } }, "status": "succeeded" @@ -48210,7 +48210,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 46.0, "wellLocation": { "offset": { @@ -48226,7 +48226,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 }, "volume": 46.0 }, @@ -48236,7 +48236,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 46.0, "wellLocation": { "offset": { @@ -48252,7 +48252,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 46.0 }, @@ -48327,7 +48327,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 } }, "status": "succeeded" @@ -48336,7 +48336,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 46.0, "wellLocation": { "offset": { @@ -48352,7 +48352,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 }, "volume": 46.0 }, @@ -48362,7 +48362,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 46.0, "wellLocation": { "offset": { @@ -48378,7 +48378,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 46.0 }, @@ -48448,7 +48448,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.5, "wellLocation": { "offset": { @@ -48474,7 +48474,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.5, "wellLocation": { "offset": { @@ -48500,7 +48500,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 40.5, "wellLocation": { "offset": { @@ -48526,7 +48526,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 40.5, "wellLocation": { "offset": { @@ -48542,7 +48542,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 40.5 }, @@ -48567,7 +48567,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -48576,7 +48576,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -48592,7 +48592,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 60.0 }, @@ -48617,7 +48617,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -48626,7 +48626,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -48642,7 +48642,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -48652,7 +48652,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -48668,7 +48668,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -48693,7 +48693,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -48702,7 +48702,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { @@ -48718,7 +48718,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 30.0 }, @@ -48728,7 +48728,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -48744,7 +48744,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 60.0 }, @@ -48769,7 +48769,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -48778,7 +48778,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -48794,7 +48794,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -48804,7 +48804,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -48820,7 +48820,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -48845,7 +48845,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -48854,7 +48854,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { @@ -48870,7 +48870,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 30.0 }, @@ -48880,7 +48880,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -49026,7 +49026,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.5, "wellLocation": { "offset": { @@ -49052,7 +49052,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.5, "wellLocation": { "offset": { @@ -49078,7 +49078,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 40.5, "wellLocation": { "offset": { @@ -49104,7 +49104,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 40.5, "wellLocation": { "offset": { @@ -49120,7 +49120,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 40.5 }, @@ -49145,7 +49145,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -49154,7 +49154,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -49170,7 +49170,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 60.0 }, @@ -49195,7 +49195,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -49204,7 +49204,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -49220,7 +49220,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -49230,7 +49230,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -49246,7 +49246,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -49271,7 +49271,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -49280,7 +49280,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { @@ -49296,7 +49296,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 30.0 }, @@ -49306,7 +49306,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -49322,7 +49322,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 60.0 }, @@ -49347,7 +49347,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -49356,7 +49356,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -49372,7 +49372,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -49382,7 +49382,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -49398,7 +49398,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -49423,7 +49423,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -49432,7 +49432,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { @@ -49448,7 +49448,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 30.0 }, @@ -49458,7 +49458,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -49604,7 +49604,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.5, "wellLocation": { "offset": { @@ -49630,7 +49630,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.5, "wellLocation": { "offset": { @@ -49656,7 +49656,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 40.5, "wellLocation": { "offset": { @@ -49682,7 +49682,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 40.5, "wellLocation": { "offset": { @@ -49698,7 +49698,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 40.5 }, @@ -49723,7 +49723,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -49732,7 +49732,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -49748,7 +49748,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 60.0 }, @@ -49773,7 +49773,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -49782,7 +49782,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -49798,7 +49798,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -49808,7 +49808,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -49824,7 +49824,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -49849,7 +49849,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -49858,7 +49858,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { @@ -49874,7 +49874,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 30.0 }, @@ -49884,7 +49884,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -49900,7 +49900,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 60.0 }, @@ -49925,7 +49925,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -49934,7 +49934,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -49950,7 +49950,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -49960,7 +49960,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -49976,7 +49976,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -50001,7 +50001,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -50010,7 +50010,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { @@ -50026,7 +50026,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 30.0 }, @@ -50036,7 +50036,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -50281,7 +50281,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -50340,7 +50340,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -50390,7 +50390,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -50425,7 +50425,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -50571,7 +50571,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -50630,7 +50630,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -50680,7 +50680,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -50715,7 +50715,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -50861,7 +50861,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -50920,7 +50920,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -50970,7 +50970,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -51005,7 +51005,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -51137,7 +51137,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -51259,7 +51259,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -51294,7 +51294,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -51440,7 +51440,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -51562,7 +51562,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -51597,7 +51597,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -51743,7 +51743,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -51865,7 +51865,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -51900,7 +51900,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -52080,7 +52080,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -52139,7 +52139,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -52189,7 +52189,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -52224,7 +52224,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -52370,7 +52370,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -52429,7 +52429,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -52479,7 +52479,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -52514,7 +52514,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -52660,7 +52660,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -52719,7 +52719,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -52769,7 +52769,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -52804,7 +52804,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -52936,7 +52936,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -53058,7 +53058,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -53093,7 +53093,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -53239,7 +53239,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -53361,7 +53361,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -53396,7 +53396,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -53542,7 +53542,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -53664,7 +53664,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -53699,7 +53699,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -53879,7 +53879,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -53938,7 +53938,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -53988,7 +53988,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -54023,7 +54023,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -54169,7 +54169,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -54228,7 +54228,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -54278,7 +54278,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -54313,7 +54313,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -54459,7 +54459,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -54518,7 +54518,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -54568,7 +54568,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -54603,7 +54603,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -54759,7 +54759,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -54785,7 +54785,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.0, "wellLocation": { "offset": { @@ -54820,7 +54820,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -54966,7 +54966,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -54992,7 +54992,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.0, "wellLocation": { "offset": { @@ -55027,7 +55027,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -55173,7 +55173,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -55199,7 +55199,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.0, "wellLocation": { "offset": { @@ -55234,7 +55234,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -55402,7 +55402,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -55452,7 +55452,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -55493,7 +55493,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -55502,7 +55502,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -55518,7 +55518,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -55552,7 +55552,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -55593,7 +55593,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -55602,7 +55602,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -55618,7 +55618,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -55652,7 +55652,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -55693,7 +55693,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -55702,7 +55702,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -55718,7 +55718,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -55752,7 +55752,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -55793,7 +55793,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -55802,7 +55802,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -55818,7 +55818,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -55828,7 +55828,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -55844,7 +55844,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -55854,7 +55854,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -56000,7 +56000,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -56050,7 +56050,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -56091,7 +56091,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -56100,7 +56100,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -56116,7 +56116,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -56150,7 +56150,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -56191,7 +56191,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -56200,7 +56200,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -56216,7 +56216,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -56250,7 +56250,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -56291,7 +56291,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -56300,7 +56300,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -56316,7 +56316,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -56350,7 +56350,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -56391,7 +56391,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -56400,7 +56400,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -56416,7 +56416,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -56426,7 +56426,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -56442,7 +56442,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -56452,7 +56452,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -56598,7 +56598,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -56648,7 +56648,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -56689,7 +56689,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -56698,7 +56698,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -56714,7 +56714,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -56748,7 +56748,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -56789,7 +56789,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -56798,7 +56798,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -56814,7 +56814,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -56848,7 +56848,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -56889,7 +56889,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -56898,7 +56898,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -56914,7 +56914,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -56948,7 +56948,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -56989,7 +56989,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -56998,7 +56998,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -57014,7 +57014,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -57024,7 +57024,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -57040,7 +57040,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -57050,7 +57050,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -57268,7 +57268,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 31.0, "wellLocation": { "offset": { @@ -57294,7 +57294,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -57310,7 +57310,7 @@ "position": { "x": 48.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 31.0 }, @@ -57394,7 +57394,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 31.0, "wellLocation": { "offset": { @@ -57420,7 +57420,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -57436,7 +57436,7 @@ "position": { "x": 57.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 31.0 }, @@ -57520,7 +57520,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 31.0, "wellLocation": { "offset": { @@ -57546,7 +57546,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -57562,7 +57562,7 @@ "position": { "x": 66.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 31.0 }, @@ -57688,7 +57688,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -57714,7 +57714,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -57740,7 +57740,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -57766,7 +57766,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -57792,7 +57792,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -57818,7 +57818,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -57844,7 +57844,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -57870,7 +57870,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -57896,7 +57896,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -57922,7 +57922,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -57948,7 +57948,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -57974,7 +57974,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -58000,7 +58000,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -58026,7 +58026,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -58052,7 +58052,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -58078,7 +58078,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -58104,7 +58104,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -58130,7 +58130,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -58156,7 +58156,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58182,7 +58182,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58198,7 +58198,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -58208,7 +58208,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58234,7 +58234,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58250,7 +58250,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -58260,7 +58260,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58286,7 +58286,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58302,7 +58302,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -58312,7 +58312,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58338,7 +58338,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58354,7 +58354,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -58364,7 +58364,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58390,7 +58390,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58406,7 +58406,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -58416,7 +58416,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58442,7 +58442,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58458,7 +58458,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -58468,7 +58468,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58494,7 +58494,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58510,7 +58510,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -58520,7 +58520,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58546,7 +58546,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58562,7 +58562,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -58572,7 +58572,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58598,7 +58598,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58614,7 +58614,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -58624,7 +58624,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58650,7 +58650,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58666,7 +58666,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -58676,7 +58676,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58702,7 +58702,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58718,7 +58718,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -58728,7 +58728,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58754,7 +58754,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58770,7 +58770,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -58780,7 +58780,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58806,7 +58806,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58822,7 +58822,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -58832,7 +58832,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58858,7 +58858,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58874,7 +58874,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -58884,7 +58884,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58910,7 +58910,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58926,7 +58926,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -58936,7 +58936,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58962,7 +58962,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -58978,7 +58978,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -58988,7 +58988,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59014,7 +59014,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59030,7 +59030,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -59040,7 +59040,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59066,7 +59066,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59082,7 +59082,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -59092,7 +59092,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59118,7 +59118,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59134,7 +59134,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -59144,7 +59144,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59170,7 +59170,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59186,7 +59186,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -59196,7 +59196,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59222,7 +59222,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59238,7 +59238,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -59248,7 +59248,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59274,7 +59274,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59290,7 +59290,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -59300,7 +59300,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59326,7 +59326,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59342,7 +59342,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -59352,7 +59352,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59378,7 +59378,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59394,7 +59394,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -59404,7 +59404,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59430,7 +59430,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59446,7 +59446,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -59456,7 +59456,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59482,7 +59482,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59498,7 +59498,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -59508,7 +59508,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59534,7 +59534,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59550,7 +59550,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -59560,7 +59560,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59586,7 +59586,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59602,7 +59602,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -59612,7 +59612,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59638,7 +59638,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59654,7 +59654,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -59664,7 +59664,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59690,7 +59690,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59706,7 +59706,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -59716,7 +59716,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59742,7 +59742,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59758,7 +59758,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -59768,7 +59768,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59794,7 +59794,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59810,7 +59810,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -59820,7 +59820,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59846,7 +59846,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59862,7 +59862,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -59872,7 +59872,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59898,7 +59898,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59914,7 +59914,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -59924,7 +59924,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59950,7 +59950,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -59966,7 +59966,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -59976,7 +59976,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -60002,7 +60002,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -60018,7 +60018,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -60028,7 +60028,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -60054,7 +60054,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -60080,7 +60080,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -60106,7 +60106,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -60132,7 +60132,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -60158,7 +60158,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -60184,7 +60184,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -60210,7 +60210,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -60236,7 +60236,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -60262,7 +60262,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -60288,7 +60288,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -60314,7 +60314,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -60340,7 +60340,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 121.5, "wellLocation": { "offset": { @@ -60366,7 +60366,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 121.5, "wellLocation": { "offset": { @@ -60392,7 +60392,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 121.5, "wellLocation": { "offset": { @@ -60418,7 +60418,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 121.5, "wellLocation": { "offset": { @@ -60444,7 +60444,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 121.5, "wellLocation": { "offset": { @@ -60470,7 +60470,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 121.5, "wellLocation": { "offset": { @@ -60496,7 +60496,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 75.0, "wellLocation": { "offset": { @@ -60522,7 +60522,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 75.0, "wellLocation": { "offset": { @@ -60548,7 +60548,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 120.0, "wellLocation": { "offset": { @@ -60574,7 +60574,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 120.0, "wellLocation": { "offset": { @@ -60650,7 +60650,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 12.0, "wellLocation": { "offset": { @@ -60676,7 +60676,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 12.0, "wellLocation": { "offset": { @@ -60702,7 +60702,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 15.0, "wellLocation": { "offset": { @@ -60728,7 +60728,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 15.0, "wellLocation": { "offset": { @@ -60754,7 +60754,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 32.0, "wellLocation": { "offset": { @@ -60770,7 +60770,7 @@ "position": { "x": 48.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 32.0 }, @@ -60780,7 +60780,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 32.0, "wellLocation": { "offset": { @@ -60806,7 +60806,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 32.0, "wellLocation": { "offset": { @@ -60822,7 +60822,7 @@ "position": { "x": 57.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 32.0 }, @@ -60832,7 +60832,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 32.0, "wellLocation": { "offset": { @@ -60858,7 +60858,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 32.0, "wellLocation": { "offset": { @@ -60874,7 +60874,7 @@ "position": { "x": 66.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 32.0 }, @@ -60884,7 +60884,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 32.0, "wellLocation": { "offset": { @@ -60910,7 +60910,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 30.0, "wellLocation": { "offset": { @@ -60936,7 +60936,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 30.0, "wellLocation": { "offset": { @@ -60952,7 +60952,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 30.0 }, @@ -60962,7 +60962,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 30.0, "wellLocation": { "offset": { @@ -60988,7 +60988,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 30.0, "wellLocation": { "offset": { @@ -61004,7 +61004,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 30.0 }, @@ -61014,7 +61014,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 30.0, "wellLocation": { "offset": { @@ -61040,7 +61040,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 30.0, "wellLocation": { "offset": { @@ -61056,7 +61056,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 30.0 }, @@ -61203,7 +61203,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 } }, "status": "succeeded" @@ -61212,7 +61212,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 101.0, "wellLocation": { "offset": { @@ -61228,7 +61228,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 }, "volume": 101.0 }, @@ -61238,7 +61238,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 101.0, "wellLocation": { "offset": { @@ -61254,7 +61254,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 101.0 }, @@ -61329,7 +61329,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 } }, "status": "succeeded" @@ -61338,7 +61338,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 101.0, "wellLocation": { "offset": { @@ -61354,7 +61354,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 }, "volume": 101.0 }, @@ -61364,7 +61364,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 101.0, "wellLocation": { "offset": { @@ -61380,7 +61380,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 101.0 }, @@ -61455,7 +61455,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 } }, "status": "succeeded" @@ -61464,7 +61464,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 101.0, "wellLocation": { "offset": { @@ -61480,7 +61480,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 }, "volume": 101.0 }, @@ -61490,7 +61490,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 101.0, "wellLocation": { "offset": { @@ -61506,7 +61506,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 101.0 }, @@ -61583,7 +61583,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -61609,7 +61609,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -61635,7 +61635,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -61661,7 +61661,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -61687,7 +61687,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -61713,7 +61713,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -61729,7 +61729,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 125.0 }, @@ -61754,7 +61754,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -61763,7 +61763,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -61779,7 +61779,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -61804,7 +61804,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -61813,7 +61813,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -61829,7 +61829,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -61839,7 +61839,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -61855,7 +61855,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -61880,7 +61880,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -61889,7 +61889,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -61905,7 +61905,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -61915,7 +61915,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -61931,7 +61931,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -61956,7 +61956,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -61965,7 +61965,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -61981,7 +61981,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -61991,7 +61991,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -62007,7 +62007,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -62032,7 +62032,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -62041,7 +62041,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -62057,7 +62057,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -62067,7 +62067,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -62213,7 +62213,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -62239,7 +62239,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -62265,7 +62265,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -62291,7 +62291,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -62317,7 +62317,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -62343,7 +62343,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -62359,7 +62359,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 125.0 }, @@ -62384,7 +62384,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -62393,7 +62393,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -62409,7 +62409,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -62434,7 +62434,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -62443,7 +62443,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -62459,7 +62459,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -62469,7 +62469,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -62485,7 +62485,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -62510,7 +62510,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -62519,7 +62519,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -62535,7 +62535,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -62545,7 +62545,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -62561,7 +62561,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -62586,7 +62586,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -62595,7 +62595,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -62611,7 +62611,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -62621,7 +62621,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -62637,7 +62637,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -62662,7 +62662,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -62671,7 +62671,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -62687,7 +62687,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -62697,7 +62697,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -62843,7 +62843,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -62869,7 +62869,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -62895,7 +62895,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -62921,7 +62921,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -62947,7 +62947,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -62973,7 +62973,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 125.0, "wellLocation": { "offset": { @@ -62989,7 +62989,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 125.0 }, @@ -63014,7 +63014,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -63023,7 +63023,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -63039,7 +63039,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -63064,7 +63064,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -63073,7 +63073,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -63089,7 +63089,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -63099,7 +63099,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -63115,7 +63115,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -63140,7 +63140,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -63149,7 +63149,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -63165,7 +63165,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -63175,7 +63175,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -63191,7 +63191,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -63216,7 +63216,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -63225,7 +63225,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -63241,7 +63241,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -63251,7 +63251,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 80.0, "wellLocation": { "offset": { @@ -63267,7 +63267,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 80.0 }, @@ -63292,7 +63292,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -63301,7 +63301,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 100.0, "wellLocation": { "offset": { @@ -63317,7 +63317,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 100.0 }, @@ -63327,7 +63327,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -63609,7 +63609,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -63635,7 +63635,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -63685,7 +63685,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -63711,7 +63711,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -63770,7 +63770,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -63794,7 +63794,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -63894,7 +63894,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -63920,7 +63920,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -63970,7 +63970,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -63996,7 +63996,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -64055,7 +64055,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -64079,7 +64079,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -64179,7 +64179,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -64205,7 +64205,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -64255,7 +64255,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -64281,7 +64281,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -64340,7 +64340,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -64364,7 +64364,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -64496,7 +64496,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -64512,7 +64512,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -64522,7 +64522,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -64538,7 +64538,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -64598,7 +64598,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -64614,7 +64614,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -64624,7 +64624,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -64640,7 +64640,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -64700,7 +64700,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -64716,7 +64716,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -64726,7 +64726,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -64742,7 +64742,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -64908,7 +64908,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -64967,7 +64967,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -65017,7 +65017,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -65052,7 +65052,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -65076,7 +65076,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -65176,7 +65176,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -65235,7 +65235,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -65285,7 +65285,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -65320,7 +65320,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -65344,7 +65344,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -65444,7 +65444,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -65503,7 +65503,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -65553,7 +65553,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -65588,7 +65588,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -65612,7 +65612,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -65734,7 +65734,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -65750,7 +65750,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -65760,7 +65760,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -65776,7 +65776,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -65836,7 +65836,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -65852,7 +65852,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -65862,7 +65862,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -65878,7 +65878,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -65938,7 +65938,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -65954,7 +65954,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -65964,7 +65964,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -65980,7 +65980,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -66146,7 +66146,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -66205,7 +66205,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -66255,7 +66255,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -66290,7 +66290,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -66314,7 +66314,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -66414,7 +66414,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -66473,7 +66473,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -66523,7 +66523,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -66558,7 +66558,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -66582,7 +66582,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -66682,7 +66682,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -66741,7 +66741,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -66791,7 +66791,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -66826,7 +66826,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -66850,7 +66850,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -66972,7 +66972,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -66988,7 +66988,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -66998,7 +66998,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -67014,7 +67014,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -67074,7 +67074,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -67090,7 +67090,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -67100,7 +67100,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -67116,7 +67116,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -67176,7 +67176,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -67192,7 +67192,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -67202,7 +67202,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -67218,7 +67218,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -67384,7 +67384,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -67443,7 +67443,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -67493,7 +67493,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -67528,7 +67528,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -67552,7 +67552,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -67652,7 +67652,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -67711,7 +67711,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -67761,7 +67761,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -67796,7 +67796,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -67820,7 +67820,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -67920,7 +67920,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -67979,7 +67979,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -68029,7 +68029,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -68064,7 +68064,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -68088,7 +68088,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -68210,7 +68210,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -68226,7 +68226,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -68236,7 +68236,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -68252,7 +68252,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -68312,7 +68312,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -68328,7 +68328,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -68338,7 +68338,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -68354,7 +68354,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -68414,7 +68414,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -68430,7 +68430,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -68440,7 +68440,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -68456,7 +68456,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 21.950000000000003 + "z": 21.95 }, "volume": 200.0 }, @@ -68559,7 +68559,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.200000000000003 + "z": 22.2 } }, "status": "succeeded" @@ -68568,7 +68568,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -68584,7 +68584,7 @@ "position": { "x": 14.3, "y": 74.15, - "z": 22.200000000000003 + "z": 22.2 }, "volume": 200.0 }, @@ -68594,7 +68594,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -68610,7 +68610,7 @@ "position": { "x": 41.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -68685,7 +68685,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.200000000000003 + "z": 22.2 } }, "status": "succeeded" @@ -68694,7 +68694,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -68710,7 +68710,7 @@ "position": { "x": 23.3, "y": 74.15, - "z": 22.200000000000003 + "z": 22.2 }, "volume": 200.0 }, @@ -68720,7 +68720,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -68736,7 +68736,7 @@ "position": { "x": 50.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -68811,7 +68811,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.200000000000003 + "z": 22.2 } }, "status": "succeeded" @@ -68820,7 +68820,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -68836,7 +68836,7 @@ "position": { "x": 32.3, "y": 74.15, - "z": 22.200000000000003 + "z": 22.2 }, "volume": 200.0 }, @@ -68846,7 +68846,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -68862,7 +68862,7 @@ "position": { "x": 59.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -68994,7 +68994,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -69053,7 +69053,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -69103,7 +69103,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -69138,7 +69138,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -69162,7 +69162,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -69262,7 +69262,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -69321,7 +69321,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -69371,7 +69371,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -69406,7 +69406,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -69430,7 +69430,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -69530,7 +69530,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -69589,7 +69589,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -69639,7 +69639,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -69674,7 +69674,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -69698,7 +69698,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -69808,7 +69808,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 50.0, "wellLocation": { "offset": { @@ -69834,7 +69834,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 50.0, "wellLocation": { "offset": { @@ -69869,7 +69869,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 57.0, "wellLocation": { "offset": { "x": 0.0, @@ -70015,7 +70015,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 50.0, "wellLocation": { "offset": { @@ -70041,7 +70041,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 50.0, "wellLocation": { "offset": { @@ -70076,7 +70076,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 57.0, "wellLocation": { "offset": { "x": 0.0, @@ -70222,7 +70222,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 50.0, "wellLocation": { "offset": { @@ -70248,7 +70248,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 50.0, "wellLocation": { "offset": { @@ -70283,7 +70283,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 57.0, "wellLocation": { "offset": { "x": 0.0, @@ -70445,7 +70445,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 23.0, "wellLocation": { "offset": { @@ -70471,7 +70471,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 23.0, "wellLocation": { "offset": { @@ -70547,7 +70547,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 23.0, "wellLocation": { "offset": { @@ -70573,7 +70573,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 23.0, "wellLocation": { "offset": { @@ -70649,7 +70649,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 23.0, "wellLocation": { "offset": { @@ -70675,7 +70675,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 23.0, "wellLocation": { "offset": { @@ -70893,7 +70893,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 22.0, "wellLocation": { "offset": { @@ -70919,7 +70919,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 22.0, "wellLocation": { "offset": { @@ -70935,7 +70935,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 22.0 }, @@ -71019,7 +71019,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 22.0, "wellLocation": { "offset": { @@ -71045,7 +71045,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 22.0, "wellLocation": { "offset": { @@ -71061,7 +71061,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 22.0 }, @@ -71145,7 +71145,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 22.0, "wellLocation": { "offset": { @@ -71171,7 +71171,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 22.0, "wellLocation": { "offset": { @@ -71187,7 +71187,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 22.0 }, @@ -71257,7 +71257,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 4.0, "wellLocation": { "offset": { @@ -71283,7 +71283,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 4.0, "wellLocation": { "offset": { @@ -71299,7 +71299,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 4.0 }, @@ -71324,7 +71324,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -71333,7 +71333,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -71349,7 +71349,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -71359,7 +71359,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -71375,7 +71375,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -71435,7 +71435,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 4.0, "wellLocation": { "offset": { @@ -71461,7 +71461,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 4.0, "wellLocation": { "offset": { @@ -71477,7 +71477,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 4.0 }, @@ -71502,7 +71502,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -71511,7 +71511,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -71527,7 +71527,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -71537,7 +71537,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -71553,7 +71553,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -71613,7 +71613,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 4.0, "wellLocation": { "offset": { @@ -71639,7 +71639,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 4.0, "wellLocation": { "offset": { @@ -71655,7 +71655,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 4.0 }, @@ -71680,7 +71680,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -71689,7 +71689,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -71705,7 +71705,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -71715,7 +71715,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -71731,7 +71731,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -71831,7 +71831,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 5.0, "wellLocation": { "offset": { @@ -71857,7 +71857,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 5.0, "wellLocation": { "offset": { @@ -71873,7 +71873,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 5.0 }, @@ -71933,7 +71933,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 5.0, "wellLocation": { "offset": { @@ -71959,7 +71959,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 5.0, "wellLocation": { "offset": { @@ -71975,7 +71975,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 5.0 }, @@ -72035,7 +72035,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 5.0, "wellLocation": { "offset": { @@ -72061,7 +72061,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 5.0, "wellLocation": { "offset": { @@ -72077,7 +72077,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 5.0 }, @@ -72147,7 +72147,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -72173,7 +72173,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -72189,7 +72189,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -72214,7 +72214,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -72223,7 +72223,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 45.0, "wellLocation": { "offset": { @@ -72239,7 +72239,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 45.0 }, @@ -72249,7 +72249,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 45.0, "wellLocation": { "offset": { @@ -72265,7 +72265,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 45.0 }, @@ -72325,7 +72325,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -72351,7 +72351,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -72367,7 +72367,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -72392,7 +72392,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -72401,7 +72401,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 45.0, "wellLocation": { "offset": { @@ -72417,7 +72417,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 45.0 }, @@ -72427,7 +72427,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 45.0, "wellLocation": { "offset": { @@ -72443,7 +72443,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 45.0 }, @@ -72503,7 +72503,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -72529,7 +72529,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -72545,7 +72545,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -72570,7 +72570,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -72579,7 +72579,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 45.0, "wellLocation": { "offset": { @@ -72595,7 +72595,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 45.0 }, @@ -72605,7 +72605,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 45.0, "wellLocation": { "offset": { @@ -72621,7 +72621,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 45.0 }, @@ -72772,7 +72772,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 } }, "status": "succeeded" @@ -72781,7 +72781,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 46.0, "wellLocation": { "offset": { @@ -72797,7 +72797,7 @@ "position": { "x": 21.375000000000004, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 }, "volume": 46.0 }, @@ -72807,7 +72807,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 46.0, "wellLocation": { "offset": { @@ -72823,7 +72823,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 46.0 }, @@ -72898,7 +72898,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 } }, "status": "succeeded" @@ -72907,7 +72907,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 46.0, "wellLocation": { "offset": { @@ -72923,7 +72923,7 @@ "position": { "x": 30.375000000000004, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 }, "volume": 46.0 }, @@ -72933,7 +72933,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 46.0, "wellLocation": { "offset": { @@ -72949,7 +72949,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 46.0 }, @@ -73024,7 +73024,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 } }, "status": "succeeded" @@ -73033,7 +73033,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 46.0, "wellLocation": { "offset": { @@ -73049,7 +73049,7 @@ "position": { "x": 39.375, "y": 356.2, - "z": 1.329999999999993 + "z": 1.33 }, "volume": 46.0 }, @@ -73059,7 +73059,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 46.0, "wellLocation": { "offset": { @@ -73075,7 +73075,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 46.0 }, @@ -73145,7 +73145,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.5, "wellLocation": { "offset": { @@ -73171,7 +73171,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.5, "wellLocation": { "offset": { @@ -73197,7 +73197,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 40.5, "wellLocation": { "offset": { @@ -73223,7 +73223,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 40.5, "wellLocation": { "offset": { @@ -73239,7 +73239,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 40.5 }, @@ -73264,7 +73264,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -73273,7 +73273,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -73289,7 +73289,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 60.0 }, @@ -73314,7 +73314,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -73323,7 +73323,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -73339,7 +73339,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -73349,7 +73349,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -73365,7 +73365,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -73390,7 +73390,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -73399,7 +73399,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { @@ -73415,7 +73415,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 30.0 }, @@ -73425,7 +73425,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -73441,7 +73441,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 60.0 }, @@ -73466,7 +73466,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -73475,7 +73475,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -73491,7 +73491,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -73501,7 +73501,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -73517,7 +73517,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -73542,7 +73542,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -73551,7 +73551,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { @@ -73567,7 +73567,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 30.0 }, @@ -73577,7 +73577,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -73723,7 +73723,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.5, "wellLocation": { "offset": { @@ -73749,7 +73749,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.5, "wellLocation": { "offset": { @@ -73775,7 +73775,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 40.5, "wellLocation": { "offset": { @@ -73801,7 +73801,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 40.5, "wellLocation": { "offset": { @@ -73817,7 +73817,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 40.5 }, @@ -73842,7 +73842,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -73851,7 +73851,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -73867,7 +73867,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 60.0 }, @@ -73892,7 +73892,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -73901,7 +73901,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -73917,7 +73917,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -73927,7 +73927,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -73943,7 +73943,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -73968,7 +73968,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -73977,7 +73977,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { @@ -73993,7 +73993,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 30.0 }, @@ -74003,7 +74003,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -74019,7 +74019,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 60.0 }, @@ -74044,7 +74044,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -74053,7 +74053,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -74069,7 +74069,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -74079,7 +74079,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -74095,7 +74095,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -74120,7 +74120,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -74129,7 +74129,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { @@ -74145,7 +74145,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 30.0 }, @@ -74155,7 +74155,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -74301,7 +74301,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.5, "wellLocation": { "offset": { @@ -74327,7 +74327,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.5, "wellLocation": { "offset": { @@ -74353,7 +74353,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 40.5, "wellLocation": { "offset": { @@ -74379,7 +74379,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 40.5, "wellLocation": { "offset": { @@ -74395,7 +74395,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 40.5 }, @@ -74420,7 +74420,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -74429,7 +74429,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -74445,7 +74445,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 60.0 }, @@ -74470,7 +74470,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -74479,7 +74479,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -74495,7 +74495,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -74505,7 +74505,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -74521,7 +74521,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -74546,7 +74546,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -74555,7 +74555,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { @@ -74571,7 +74571,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 30.0 }, @@ -74581,7 +74581,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -74597,7 +74597,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 60.0 }, @@ -74622,7 +74622,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -74631,7 +74631,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -74647,7 +74647,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -74657,7 +74657,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { @@ -74673,7 +74673,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 60.0 }, @@ -74698,7 +74698,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 } }, "status": "succeeded" @@ -74707,7 +74707,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { @@ -74723,7 +74723,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 26.950000000000003 + "z": 26.95 }, "volume": 30.0 }, @@ -74733,7 +74733,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -74978,7 +74978,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -75037,7 +75037,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -75087,7 +75087,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -75122,7 +75122,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -75268,7 +75268,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -75327,7 +75327,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -75377,7 +75377,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -75412,7 +75412,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -75558,7 +75558,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -75617,7 +75617,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -75667,7 +75667,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -75702,7 +75702,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -75834,7 +75834,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -75956,7 +75956,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -75991,7 +75991,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -76137,7 +76137,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -76259,7 +76259,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -76294,7 +76294,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -76440,7 +76440,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -76562,7 +76562,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -76597,7 +76597,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -76777,7 +76777,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -76836,7 +76836,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -76886,7 +76886,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -76921,7 +76921,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -77067,7 +77067,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -77126,7 +77126,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -77176,7 +77176,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -77211,7 +77211,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -77357,7 +77357,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -77416,7 +77416,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -77466,7 +77466,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -77501,7 +77501,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -77633,7 +77633,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -77755,7 +77755,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -77790,7 +77790,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -77936,7 +77936,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -78058,7 +78058,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -78093,7 +78093,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -78239,7 +78239,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -78361,7 +78361,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -78396,7 +78396,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -78576,7 +78576,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -78635,7 +78635,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -78685,7 +78685,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -78720,7 +78720,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -78866,7 +78866,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -78925,7 +78925,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -78975,7 +78975,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -79010,7 +79010,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -79156,7 +79156,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -79215,7 +79215,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -79265,7 +79265,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -79300,7 +79300,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -79456,7 +79456,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -79482,7 +79482,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.0, "wellLocation": { "offset": { @@ -79517,7 +79517,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -79663,7 +79663,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -79689,7 +79689,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.0, "wellLocation": { "offset": { @@ -79724,7 +79724,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -79870,7 +79870,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -79896,7 +79896,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.0, "wellLocation": { "offset": { @@ -79931,7 +79931,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -80099,7 +80099,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -80149,7 +80149,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -80190,7 +80190,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -80199,7 +80199,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -80215,7 +80215,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -80249,7 +80249,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -80290,7 +80290,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -80299,7 +80299,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -80315,7 +80315,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -80349,7 +80349,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -80390,7 +80390,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -80399,7 +80399,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -80415,7 +80415,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -80449,7 +80449,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -80490,7 +80490,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -80499,7 +80499,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -80515,7 +80515,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -80525,7 +80525,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -80541,7 +80541,7 @@ "position": { "x": 68.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -80551,7 +80551,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -80697,7 +80697,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -80747,7 +80747,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -80788,7 +80788,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -80797,7 +80797,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -80813,7 +80813,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -80847,7 +80847,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -80888,7 +80888,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -80897,7 +80897,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -80913,7 +80913,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -80947,7 +80947,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -80988,7 +80988,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -80997,7 +80997,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -81013,7 +81013,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -81047,7 +81047,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -81088,7 +81088,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -81097,7 +81097,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -81113,7 +81113,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -81123,7 +81123,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -81139,7 +81139,7 @@ "position": { "x": 77.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -81149,7 +81149,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -81295,7 +81295,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -81345,7 +81345,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -81386,7 +81386,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -81395,7 +81395,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -81411,7 +81411,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -81445,7 +81445,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -81486,7 +81486,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -81495,7 +81495,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -81511,7 +81511,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -81545,7 +81545,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -81586,7 +81586,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -81595,7 +81595,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -81611,7 +81611,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -81645,7 +81645,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -81686,7 +81686,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 } }, "status": "succeeded" @@ -81695,7 +81695,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -81711,7 +81711,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -81721,7 +81721,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -81737,7 +81737,7 @@ "position": { "x": 86.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 32.0 }, @@ -81747,7 +81747,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -81965,7 +81965,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 31.0, "wellLocation": { "offset": { @@ -81991,7 +81991,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -82007,7 +82007,7 @@ "position": { "x": 48.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 31.0 }, @@ -82091,7 +82091,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 31.0, "wellLocation": { "offset": { @@ -82117,7 +82117,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -82133,7 +82133,7 @@ "position": { "x": 57.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 31.0 }, @@ -82217,7 +82217,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 31.0, "wellLocation": { "offset": { @@ -82243,7 +82243,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -82259,7 +82259,7 @@ "position": { "x": 66.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 31.0 }, @@ -82385,7 +82385,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -82411,7 +82411,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -82437,7 +82437,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -82463,7 +82463,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -82489,7 +82489,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -82515,7 +82515,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -82541,7 +82541,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -82567,7 +82567,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -82593,7 +82593,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -82619,7 +82619,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -82645,7 +82645,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -82671,7 +82671,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -82697,7 +82697,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -82723,7 +82723,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -82749,7 +82749,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -82775,7 +82775,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -82801,7 +82801,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -82827,7 +82827,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 125.0, "wellLocation": { "offset": { @@ -82853,7 +82853,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -82879,7 +82879,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -82895,7 +82895,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -82905,7 +82905,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -82931,7 +82931,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -82947,7 +82947,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -82957,7 +82957,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -82983,7 +82983,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -82999,7 +82999,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -83009,7 +83009,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83035,7 +83035,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83051,7 +83051,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -83061,7 +83061,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83087,7 +83087,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83103,7 +83103,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -83113,7 +83113,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83139,7 +83139,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83155,7 +83155,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -83165,7 +83165,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83191,7 +83191,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83207,7 +83207,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -83217,7 +83217,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83243,7 +83243,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83259,7 +83259,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -83269,7 +83269,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83295,7 +83295,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83311,7 +83311,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -83321,7 +83321,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83347,7 +83347,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83363,7 +83363,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -83373,7 +83373,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83399,7 +83399,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83415,7 +83415,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -83425,7 +83425,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83451,7 +83451,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83467,7 +83467,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -83477,7 +83477,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83503,7 +83503,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83519,7 +83519,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -83529,7 +83529,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83555,7 +83555,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83571,7 +83571,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -83581,7 +83581,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83607,7 +83607,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83623,7 +83623,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -83633,7 +83633,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83659,7 +83659,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83675,7 +83675,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -83685,7 +83685,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83711,7 +83711,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83727,7 +83727,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -83737,7 +83737,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83763,7 +83763,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83779,7 +83779,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -83789,7 +83789,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83815,7 +83815,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83831,7 +83831,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -83841,7 +83841,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83867,7 +83867,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83883,7 +83883,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -83893,7 +83893,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83919,7 +83919,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83935,7 +83935,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -83945,7 +83945,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83971,7 +83971,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -83987,7 +83987,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -83997,7 +83997,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84023,7 +84023,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84039,7 +84039,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -84049,7 +84049,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84075,7 +84075,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84091,7 +84091,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -84101,7 +84101,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84127,7 +84127,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84143,7 +84143,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -84153,7 +84153,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84179,7 +84179,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84195,7 +84195,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -84205,7 +84205,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84231,7 +84231,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84247,7 +84247,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -84257,7 +84257,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84283,7 +84283,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84299,7 +84299,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -84309,7 +84309,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84335,7 +84335,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84351,7 +84351,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -84361,7 +84361,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84387,7 +84387,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84403,7 +84403,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -84413,7 +84413,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84439,7 +84439,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84455,7 +84455,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -84465,7 +84465,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84491,7 +84491,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84507,7 +84507,7 @@ "position": { "x": 95.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -84517,7 +84517,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84543,7 +84543,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84559,7 +84559,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -84569,7 +84569,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84595,7 +84595,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84611,7 +84611,7 @@ "position": { "x": 104.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -84621,7 +84621,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84647,7 +84647,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84663,7 +84663,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -84673,7 +84673,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84699,7 +84699,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -84715,7 +84715,7 @@ "position": { "x": 113.3, "y": 74.15, - "z": 22.950000000000003 + "z": 22.95 }, "volume": 200.0 }, @@ -84725,7 +84725,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -84751,7 +84751,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -84777,7 +84777,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -84803,7 +84803,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -84829,7 +84829,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -84855,7 +84855,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -84881,7 +84881,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -84907,7 +84907,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -84933,7 +84933,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -84959,7 +84959,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -84985,7 +84985,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -85011,7 +85011,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -85037,7 +85037,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 121.5, "wellLocation": { "offset": { @@ -85063,7 +85063,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 121.5, "wellLocation": { "offset": { @@ -85089,7 +85089,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 121.5, "wellLocation": { "offset": { @@ -85115,7 +85115,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 121.5, "wellLocation": { "offset": { @@ -85141,7 +85141,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 121.5, "wellLocation": { "offset": { @@ -85167,7 +85167,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 121.5, "wellLocation": { "offset": { @@ -85193,7 +85193,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 75.0, "wellLocation": { "offset": { @@ -85219,7 +85219,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 75.0, "wellLocation": { "offset": { @@ -85245,7 +85245,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 120.0, "wellLocation": { "offset": { @@ -85271,7 +85271,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 120.0, "wellLocation": { "offset": { @@ -85347,7 +85347,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 12.0, "wellLocation": { "offset": { @@ -85373,7 +85373,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 12.0, "wellLocation": { "offset": { @@ -85399,7 +85399,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 15.0, "wellLocation": { "offset": { @@ -85425,7 +85425,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 15.0, "wellLocation": { "offset": { @@ -85451,7 +85451,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 32.0, "wellLocation": { "offset": { @@ -85467,7 +85467,7 @@ "position": { "x": 48.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 32.0 }, @@ -85477,7 +85477,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 32.0, "wellLocation": { "offset": { @@ -85503,7 +85503,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 32.0, "wellLocation": { "offset": { @@ -85519,7 +85519,7 @@ "position": { "x": 57.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 32.0 }, @@ -85529,7 +85529,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 32.0, "wellLocation": { "offset": { @@ -85555,7 +85555,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 32.0, "wellLocation": { "offset": { @@ -85571,7 +85571,7 @@ "position": { "x": 66.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 32.0 }, @@ -85581,7 +85581,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 32.0, "wellLocation": { "offset": { @@ -85607,7 +85607,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 30.0, "wellLocation": { "offset": { @@ -85633,7 +85633,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 30.0, "wellLocation": { "offset": { @@ -85649,7 +85649,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 30.0 }, @@ -85659,7 +85659,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 30.0, "wellLocation": { "offset": { @@ -85685,7 +85685,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 30.0, "wellLocation": { "offset": { @@ -85701,7 +85701,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 30.0 }, @@ -85711,7 +85711,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 30.0, "wellLocation": { "offset": { @@ -85737,7 +85737,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 30.0, "wellLocation": { "offset": { @@ -85753,7 +85753,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 30.0 }, @@ -85794,7 +85794,7 @@ "errors": [], "files": [ { - "name": "Flex_P1000MLeft_P50MRight_HS_MM_TC_TM_2_15_ABR3_Illumina_DNA_Enrichment_v4.py", + "name": "Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAEnrichmentv4.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4e17da0b57][Flex_P1000_96_Gripper_TC_TM_HS_AnalysisError_GripperCollisionWithTips].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[19c783e363][Flex_X_v8_P1000_96_HS_GRIP_TC_TM_GripperCollisionWithTips].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4e17da0b57][Flex_P1000_96_Gripper_TC_TM_HS_AnalysisError_GripperCollisionWithTips].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[19c783e363][Flex_X_v8_P1000_96_HS_GRIP_TC_TM_GripperCollisionWithTips].json index babe140d830..f309752b497 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4e17da0b57][Flex_P1000_96_Gripper_TC_TM_HS_AnalysisError_GripperCollisionWithTips].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[19c783e363][Flex_X_v8_P1000_96_HS_GRIP_TC_TM_GripperCollisionWithTips].json @@ -12269,7 +12269,7 @@ ], "files": [ { - "name": "Flex_P1000_96_Gripper_TC_TM_HS_AnalysisError_GripperCollisionWithTips.json", + "name": "Flex_X_v8_P1000_96_HS_GRIP_TC_TM_GripperCollisionWithTips.json", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[3b1bfd0d2d][OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin2].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[19ffa9c839][OT2_X_v2_16_None_None_HS_HeaterShakerConflictWithTrashBin2].json similarity index 92% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[3b1bfd0d2d][OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin2].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[19ffa9c839][OT2_X_v2_16_None_None_HS_HeaterShakerConflictWithTrashBin2].json index a8091a65bdd..f0d76705138 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[3b1bfd0d2d][OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin2].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[19ffa9c839][OT2_X_v2_16_None_None_HS_HeaterShakerConflictWithTrashBin2].json @@ -478,7 +478,7 @@ "errorInfo": { "args": "('trash bin in slot 12 prevents heaterShakerModuleV1 from using slot 9.',)", "class": "DeckConflictError", - "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin2.py\", line 11, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line 383, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/protocol_context.py\", line 814, in load_module\n module_core = self._core.load_module(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/engine/protocol.py\", line 424, in load_module\n deck_conflict.check(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/engine/deck_conflict.py\", line 203, in check\n wrapped_deck_conflict.check(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/motion_planning/deck_conflict.py\", line 210, in check\n raise DeckConflictError(\n" + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"OT2_X_v2_16_None_None_HS_HeaterShakerConflictWithTrashBin2.py\", line 11, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line 383, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/protocol_context.py\", line 814, in load_module\n module_core = self._core.load_module(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/engine/protocol.py\", line 423, in load_module\n deck_conflict.check(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/engine/deck_conflict.py\", line 203, in check\n wrapped_deck_conflict.check(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/motion_planning/deck_conflict.py\", line 210, in check\n raise DeckConflictError(\n" }, "errorType": "PythonException", "wrappedErrors": [] @@ -488,7 +488,7 @@ ], "files": [ { - "name": "OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin2.py", + "name": "OT2_X_v2_16_None_None_HS_HeaterShakerConflictWithTrashBin2.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1c19a2055c][OT2_S_v2_4_P300M_None_MM_TM_Zymo].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1c19a2055c][OT2_S_v2_4_P300M_None_MM_TM_Zymo].json new file mode 100644 index 00000000000..54039a6738b --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1c19a2055c][OT2_S_v2_4_P300M_None_MM_TM_Zymo].json @@ -0,0 +1,65233 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "loadModule", + "notes": [], + "params": { + "location": { + "slotName": "6" + }, + "model": "magneticModuleV2" + }, + "result": { + "definition": { + "calibrationPoint": { + "x": 124.875, + "y": 2.75, + "z": 82.25 + }, + "compatibleWith": [], + "dimensions": { + "bareOverallHeight": 110.152, + "overLabwareHeight": 4.052 + }, + "displayName": "Magnetic Module GEN2", + "gripperOffsets": {}, + "labwareOffset": { + "x": -1.175, + "y": -0.125, + "z": 82.25 + }, + "model": "magneticModuleV2", + "moduleType": "magneticModuleType", + "otSharedSchema": "module/schemas/2", + "quirks": [], + "slotTransforms": { + "ot2_short_trash": { + "3": { + "labwareOffset": [ + [ + -1, + 0, + 0, + 0.3 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ] + ] + }, + "6": { + "labwareOffset": [ + [ + -1, + 0, + 0, + 0.3 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ] + ] + }, + "9": { + "labwareOffset": [ + [ + -1, + 0, + 0, + 0.3 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ] + ] + } + }, + "ot2_standard": { + "3": { + "labwareOffset": [ + [ + -1, + 0, + 0, + 0.25 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ] + ] + }, + "6": { + "labwareOffset": [ + [ + -1, + 0, + 0, + 0.25 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ] + ] + }, + "9": { + "labwareOffset": [ + [ + -1, + 0, + 0, + 0.25 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ] + ] + } + } + } + }, + "model": "magneticModuleV2" + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Disengaging Magnetic Module", + "legacyCommandType": "command.MAGDECK_DISENGAGE" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "loadLabware", + "notes": [], + "params": { + "displayName": "deepwell plate", + "loadName": "nest_96_wellplate_2ml_deep", + "location": {}, + "namespace": "opentrons", + "version": 1 + }, + "result": { + "definition": { + "allowedRoles": [], + "brand": { + "brand": "NEST", + "brandId": [ + "503001", + "503501" + ], + "links": [ + "https://www.nest-biotech.com/deep-well-plates/59253726.html" + ] + }, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + }, + "dimensions": { + "xDimension": 127.6, + "yDimension": 85.3, + "zDimension": 41 + }, + "gripperOffsets": {}, + "groups": [ + { + "brand": { + "brand": "NEST", + "brandId": [] + }, + "metadata": { + "displayCategory": "wellPlate", + "displayName": "NEST 96 Deep Well Plate 2mL", + "wellBottomShape": "v" + }, + "wells": [ + "A1", + "A10", + "A11", + "A12", + "A2", + "A3", + "A4", + "A5", + "A6", + "A7", + "A8", + "A9", + "B1", + "B10", + "B11", + "B12", + "B2", + "B3", + "B4", + "B5", + "B6", + "B7", + "B8", + "B9", + "C1", + "C10", + "C11", + "C12", + "C2", + "C3", + "C4", + "C5", + "C6", + "C7", + "C8", + "C9", + "D1", + "D10", + "D11", + "D12", + "D2", + "D3", + "D4", + "D5", + "D6", + "D7", + "D8", + "D9", + "E1", + "E10", + "E11", + "E12", + "E2", + "E3", + "E4", + "E5", + "E6", + "E7", + "E8", + "E9", + "F1", + "F10", + "F11", + "F12", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + "F8", + "F9", + "G1", + "G10", + "G11", + "G12", + "G2", + "G3", + "G4", + "G5", + "G6", + "G7", + "G8", + "G9", + "H1", + "H10", + "H11", + "H12", + "H2", + "H3", + "H4", + "H5", + "H6", + "H7", + "H8", + "H9" + ] + } + ], + "metadata": { + "displayCategory": "wellPlate", + "displayName": "NEST 96 Deep Well Plate 2mL", + "displayVolumeUnits": "µL", + "tags": [] + }, + "namespace": "opentrons", + "ordering": [ + [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1" + ], + [ + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10" + ], + [ + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11" + ], + [ + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ], + [ + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2" + ], + [ + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3" + ], + [ + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4" + ], + [ + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5" + ], + [ + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6" + ], + [ + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7" + ], + [ + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8" + ], + [ + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9" + ] + ], + "parameters": { + "format": "96Standard", + "isMagneticModuleCompatible": true, + "isTiprack": false, + "loadName": "nest_96_wellplate_2ml_deep", + "magneticModuleEngageHeight": 6.8, + "quirks": [] + }, + "schemaVersion": 2, + "stackingOffsetWithLabware": {}, + "stackingOffsetWithModule": {}, + "version": 1, + "wells": { + "A1": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 14.3, + "xDimension": 8.2, + "y": 74.15, + "yDimension": 8.2, + "z": 3 + }, + "A10": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 95.3, + "xDimension": 8.2, + "y": 74.15, + "yDimension": 8.2, + "z": 3 + }, + "A11": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 104.3, + "xDimension": 8.2, + "y": 74.15, + "yDimension": 8.2, + "z": 3 + }, + "A12": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 113.3, + "xDimension": 8.2, + "y": 74.15, + "yDimension": 8.2, + "z": 3 + }, + "A2": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 23.3, + "xDimension": 8.2, + "y": 74.15, + "yDimension": 8.2, + "z": 3 + }, + "A3": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 32.3, + "xDimension": 8.2, + "y": 74.15, + "yDimension": 8.2, + "z": 3 + }, + "A4": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 41.3, + "xDimension": 8.2, + "y": 74.15, + "yDimension": 8.2, + "z": 3 + }, + "A5": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 50.3, + "xDimension": 8.2, + "y": 74.15, + "yDimension": 8.2, + "z": 3 + }, + "A6": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 59.3, + "xDimension": 8.2, + "y": 74.15, + "yDimension": 8.2, + "z": 3 + }, + "A7": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 68.3, + "xDimension": 8.2, + "y": 74.15, + "yDimension": 8.2, + "z": 3 + }, + "A8": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 77.3, + "xDimension": 8.2, + "y": 74.15, + "yDimension": 8.2, + "z": 3 + }, + "A9": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 86.3, + "xDimension": 8.2, + "y": 74.15, + "yDimension": 8.2, + "z": 3 + }, + "B1": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 14.3, + "xDimension": 8.2, + "y": 65.15, + "yDimension": 8.2, + "z": 3 + }, + "B10": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 95.3, + "xDimension": 8.2, + "y": 65.15, + "yDimension": 8.2, + "z": 3 + }, + "B11": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 104.3, + "xDimension": 8.2, + "y": 65.15, + "yDimension": 8.2, + "z": 3 + }, + "B12": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 113.3, + "xDimension": 8.2, + "y": 65.15, + "yDimension": 8.2, + "z": 3 + }, + "B2": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 23.3, + "xDimension": 8.2, + "y": 65.15, + "yDimension": 8.2, + "z": 3 + }, + "B3": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 32.3, + "xDimension": 8.2, + "y": 65.15, + "yDimension": 8.2, + "z": 3 + }, + "B4": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 41.3, + "xDimension": 8.2, + "y": 65.15, + "yDimension": 8.2, + "z": 3 + }, + "B5": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 50.3, + "xDimension": 8.2, + "y": 65.15, + "yDimension": 8.2, + "z": 3 + }, + "B6": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 59.3, + "xDimension": 8.2, + "y": 65.15, + "yDimension": 8.2, + "z": 3 + }, + "B7": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 68.3, + "xDimension": 8.2, + "y": 65.15, + "yDimension": 8.2, + "z": 3 + }, + "B8": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 77.3, + "xDimension": 8.2, + "y": 65.15, + "yDimension": 8.2, + "z": 3 + }, + "B9": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 86.3, + "xDimension": 8.2, + "y": 65.15, + "yDimension": 8.2, + "z": 3 + }, + "C1": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 14.3, + "xDimension": 8.2, + "y": 56.15, + "yDimension": 8.2, + "z": 3 + }, + "C10": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 95.3, + "xDimension": 8.2, + "y": 56.15, + "yDimension": 8.2, + "z": 3 + }, + "C11": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 104.3, + "xDimension": 8.2, + "y": 56.15, + "yDimension": 8.2, + "z": 3 + }, + "C12": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 113.3, + "xDimension": 8.2, + "y": 56.15, + "yDimension": 8.2, + "z": 3 + }, + "C2": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 23.3, + "xDimension": 8.2, + "y": 56.15, + "yDimension": 8.2, + "z": 3 + }, + "C3": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 32.3, + "xDimension": 8.2, + "y": 56.15, + "yDimension": 8.2, + "z": 3 + }, + "C4": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 41.3, + "xDimension": 8.2, + "y": 56.15, + "yDimension": 8.2, + "z": 3 + }, + "C5": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 50.3, + "xDimension": 8.2, + "y": 56.15, + "yDimension": 8.2, + "z": 3 + }, + "C6": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 59.3, + "xDimension": 8.2, + "y": 56.15, + "yDimension": 8.2, + "z": 3 + }, + "C7": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 68.3, + "xDimension": 8.2, + "y": 56.15, + "yDimension": 8.2, + "z": 3 + }, + "C8": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 77.3, + "xDimension": 8.2, + "y": 56.15, + "yDimension": 8.2, + "z": 3 + }, + "C9": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 86.3, + "xDimension": 8.2, + "y": 56.15, + "yDimension": 8.2, + "z": 3 + }, + "D1": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 14.3, + "xDimension": 8.2, + "y": 47.15, + "yDimension": 8.2, + "z": 3 + }, + "D10": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 95.3, + "xDimension": 8.2, + "y": 47.15, + "yDimension": 8.2, + "z": 3 + }, + "D11": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 104.3, + "xDimension": 8.2, + "y": 47.15, + "yDimension": 8.2, + "z": 3 + }, + "D12": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 113.3, + "xDimension": 8.2, + "y": 47.15, + "yDimension": 8.2, + "z": 3 + }, + "D2": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 23.3, + "xDimension": 8.2, + "y": 47.15, + "yDimension": 8.2, + "z": 3 + }, + "D3": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 32.3, + "xDimension": 8.2, + "y": 47.15, + "yDimension": 8.2, + "z": 3 + }, + "D4": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 41.3, + "xDimension": 8.2, + "y": 47.15, + "yDimension": 8.2, + "z": 3 + }, + "D5": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 50.3, + "xDimension": 8.2, + "y": 47.15, + "yDimension": 8.2, + "z": 3 + }, + "D6": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 59.3, + "xDimension": 8.2, + "y": 47.15, + "yDimension": 8.2, + "z": 3 + }, + "D7": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 68.3, + "xDimension": 8.2, + "y": 47.15, + "yDimension": 8.2, + "z": 3 + }, + "D8": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 77.3, + "xDimension": 8.2, + "y": 47.15, + "yDimension": 8.2, + "z": 3 + }, + "D9": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 86.3, + "xDimension": 8.2, + "y": 47.15, + "yDimension": 8.2, + "z": 3 + }, + "E1": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 14.3, + "xDimension": 8.2, + "y": 38.15, + "yDimension": 8.2, + "z": 3 + }, + "E10": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 95.3, + "xDimension": 8.2, + "y": 38.15, + "yDimension": 8.2, + "z": 3 + }, + "E11": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 104.3, + "xDimension": 8.2, + "y": 38.15, + "yDimension": 8.2, + "z": 3 + }, + "E12": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 113.3, + "xDimension": 8.2, + "y": 38.15, + "yDimension": 8.2, + "z": 3 + }, + "E2": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 23.3, + "xDimension": 8.2, + "y": 38.15, + "yDimension": 8.2, + "z": 3 + }, + "E3": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 32.3, + "xDimension": 8.2, + "y": 38.15, + "yDimension": 8.2, + "z": 3 + }, + "E4": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 41.3, + "xDimension": 8.2, + "y": 38.15, + "yDimension": 8.2, + "z": 3 + }, + "E5": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 50.3, + "xDimension": 8.2, + "y": 38.15, + "yDimension": 8.2, + "z": 3 + }, + "E6": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 59.3, + "xDimension": 8.2, + "y": 38.15, + "yDimension": 8.2, + "z": 3 + }, + "E7": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 68.3, + "xDimension": 8.2, + "y": 38.15, + "yDimension": 8.2, + "z": 3 + }, + "E8": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 77.3, + "xDimension": 8.2, + "y": 38.15, + "yDimension": 8.2, + "z": 3 + }, + "E9": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 86.3, + "xDimension": 8.2, + "y": 38.15, + "yDimension": 8.2, + "z": 3 + }, + "F1": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 14.3, + "xDimension": 8.2, + "y": 29.15, + "yDimension": 8.2, + "z": 3 + }, + "F10": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 95.3, + "xDimension": 8.2, + "y": 29.15, + "yDimension": 8.2, + "z": 3 + }, + "F11": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 104.3, + "xDimension": 8.2, + "y": 29.15, + "yDimension": 8.2, + "z": 3 + }, + "F12": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 113.3, + "xDimension": 8.2, + "y": 29.15, + "yDimension": 8.2, + "z": 3 + }, + "F2": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 23.3, + "xDimension": 8.2, + "y": 29.15, + "yDimension": 8.2, + "z": 3 + }, + "F3": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 32.3, + "xDimension": 8.2, + "y": 29.15, + "yDimension": 8.2, + "z": 3 + }, + "F4": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 41.3, + "xDimension": 8.2, + "y": 29.15, + "yDimension": 8.2, + "z": 3 + }, + "F5": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 50.3, + "xDimension": 8.2, + "y": 29.15, + "yDimension": 8.2, + "z": 3 + }, + "F6": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 59.3, + "xDimension": 8.2, + "y": 29.15, + "yDimension": 8.2, + "z": 3 + }, + "F7": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 68.3, + "xDimension": 8.2, + "y": 29.15, + "yDimension": 8.2, + "z": 3 + }, + "F8": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 77.3, + "xDimension": 8.2, + "y": 29.15, + "yDimension": 8.2, + "z": 3 + }, + "F9": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 86.3, + "xDimension": 8.2, + "y": 29.15, + "yDimension": 8.2, + "z": 3 + }, + "G1": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 14.3, + "xDimension": 8.2, + "y": 20.15, + "yDimension": 8.2, + "z": 3 + }, + "G10": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 95.3, + "xDimension": 8.2, + "y": 20.15, + "yDimension": 8.2, + "z": 3 + }, + "G11": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 104.3, + "xDimension": 8.2, + "y": 20.15, + "yDimension": 8.2, + "z": 3 + }, + "G12": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 113.3, + "xDimension": 8.2, + "y": 20.15, + "yDimension": 8.2, + "z": 3 + }, + "G2": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 23.3, + "xDimension": 8.2, + "y": 20.15, + "yDimension": 8.2, + "z": 3 + }, + "G3": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 32.3, + "xDimension": 8.2, + "y": 20.15, + "yDimension": 8.2, + "z": 3 + }, + "G4": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 41.3, + "xDimension": 8.2, + "y": 20.15, + "yDimension": 8.2, + "z": 3 + }, + "G5": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 50.3, + "xDimension": 8.2, + "y": 20.15, + "yDimension": 8.2, + "z": 3 + }, + "G6": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 59.3, + "xDimension": 8.2, + "y": 20.15, + "yDimension": 8.2, + "z": 3 + }, + "G7": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 68.3, + "xDimension": 8.2, + "y": 20.15, + "yDimension": 8.2, + "z": 3 + }, + "G8": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 77.3, + "xDimension": 8.2, + "y": 20.15, + "yDimension": 8.2, + "z": 3 + }, + "G9": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 86.3, + "xDimension": 8.2, + "y": 20.15, + "yDimension": 8.2, + "z": 3 + }, + "H1": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 14.3, + "xDimension": 8.2, + "y": 11.15, + "yDimension": 8.2, + "z": 3 + }, + "H10": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 95.3, + "xDimension": 8.2, + "y": 11.15, + "yDimension": 8.2, + "z": 3 + }, + "H11": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 104.3, + "xDimension": 8.2, + "y": 11.15, + "yDimension": 8.2, + "z": 3 + }, + "H12": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 113.3, + "xDimension": 8.2, + "y": 11.15, + "yDimension": 8.2, + "z": 3 + }, + "H2": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 23.3, + "xDimension": 8.2, + "y": 11.15, + "yDimension": 8.2, + "z": 3 + }, + "H3": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 32.3, + "xDimension": 8.2, + "y": 11.15, + "yDimension": 8.2, + "z": 3 + }, + "H4": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 41.3, + "xDimension": 8.2, + "y": 11.15, + "yDimension": 8.2, + "z": 3 + }, + "H5": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 50.3, + "xDimension": 8.2, + "y": 11.15, + "yDimension": 8.2, + "z": 3 + }, + "H6": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 59.3, + "xDimension": 8.2, + "y": 11.15, + "yDimension": 8.2, + "z": 3 + }, + "H7": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 68.3, + "xDimension": 8.2, + "y": 11.15, + "yDimension": 8.2, + "z": 3 + }, + "H8": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 77.3, + "xDimension": 8.2, + "y": 11.15, + "yDimension": 8.2, + "z": 3 + }, + "H9": { + "depth": 38, + "shape": "rectangular", + "totalLiquidVolume": 2000, + "x": 86.3, + "xDimension": 8.2, + "y": 11.15, + "yDimension": 8.2, + "z": 3 + } + } + } + }, + "status": "succeeded" + }, + { + "commandType": "loadModule", + "notes": [], + "params": { + "location": { + "slotName": "1" + }, + "model": "temperatureModuleV2" + }, + "result": { + "definition": { + "calibrationPoint": { + "x": 11.7, + "y": 8.75, + "z": 80.09 + }, + "compatibleWith": [ + "temperatureModuleV1" + ], + "dimensions": { + "bareOverallHeight": 84.0, + "overLabwareHeight": 0.0 + }, + "displayName": "Temperature Module GEN2", + "gripperOffsets": { + "default": { + "dropOffset": { + "x": 0.0, + "y": 0.0, + "z": 1.0 + }, + "pickUpOffset": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + } + }, + "labwareOffset": { + "x": -1.45, + "y": -0.15, + "z": 80.09 + }, + "model": "temperatureModuleV2", + "moduleType": "temperatureModuleType", + "otSharedSchema": "module/schemas/2", + "quirks": [], + "slotTransforms": { + "ot2_short_trash": { + "3": { + "labwareOffset": [ + [ + -1, + -0.15, + 0, + 0 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ] + ] + }, + "6": { + "labwareOffset": [ + [ + -1, + -0.15, + 0, + 0 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ] + ] + }, + "9": { + "labwareOffset": [ + [ + -1, + -0.15, + 0, + 0 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ] + ] + } + }, + "ot2_standard": { + "3": { + "labwareOffset": [ + [ + -1, + -0.3, + 0, + 0 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ] + ] + }, + "6": { + "labwareOffset": [ + [ + -1, + -0.3, + 0, + 0 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ] + ] + }, + "9": { + "labwareOffset": [ + [ + -1, + -0.3, + 0, + 0 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ] + ] + } + }, + "ot3_standard": { + "A1": { + "labwareOffset": [ + [ + -71.09, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0.15, + 1 + ], + [ + 0, + 0, + 1, + 1.45 + ] + ] + }, + "A3": { + "labwareOffset": [ + [ + -71.09, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0.15, + 1 + ], + [ + 0, + 0, + 1, + 1.45 + ] + ] + }, + "B1": { + "labwareOffset": [ + [ + -71.09, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0.15, + 1 + ], + [ + 0, + 0, + 1, + 1.45 + ] + ] + }, + "B3": { + "labwareOffset": [ + [ + -71.09, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0.15, + 1 + ], + [ + 0, + 0, + 1, + 1.45 + ] + ] + }, + "C1": { + "labwareOffset": [ + [ + -71.09, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0.15, + 1 + ], + [ + 0, + 0, + 1, + 1.45 + ] + ] + }, + "C3": { + "labwareOffset": [ + [ + -71.09, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0.15, + 1 + ], + [ + 0, + 0, + 1, + 1.45 + ] + ] + }, + "D1": { + "labwareOffset": [ + [ + -71.09, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0.15, + 1 + ], + [ + 0, + 0, + 1, + 1.45 + ] + ] + }, + "D3": { + "labwareOffset": [ + [ + -71.09, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0, + 1 + ], + [ + 0, + 0, + 0.15, + 1 + ], + [ + 0, + 0, + 1, + 1.45 + ] + ] + } + } + } + }, + "model": "temperatureModuleV2" + }, + "status": "succeeded" + }, + { + "commandType": "loadLabware", + "notes": [], + "params": { + "loadName": "opentrons_96_aluminumblock_nest_wellplate_100ul", + "location": {}, + "namespace": "opentrons", + "version": 1 + }, + "result": { + "definition": { + "allowedRoles": [], + "brand": { + "brand": "Opentrons", + "brandId": [], + "links": [ + "https://shop.opentrons.com/collections/hardware-modules/products/aluminum-block-set" + ] + }, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + }, + "dimensions": { + "xDimension": 127.75, + "yDimension": 85.45, + "zDimension": 21.2 + }, + "gripperOffsets": {}, + "groups": [ + { + "brand": { + "brand": "NEST", + "brandId": [ + "402501" + ], + "links": [ + "https://www.nest-biotech.com/pcr-plates/58773587.html" + ] + }, + "metadata": { + "displayCategory": "wellPlate", + "displayName": "NEST 96 Well Plate 100 µL", + "wellBottomShape": "v" + }, + "wells": [ + "A1", + "A10", + "A11", + "A12", + "A2", + "A3", + "A4", + "A5", + "A6", + "A7", + "A8", + "A9", + "B1", + "B10", + "B11", + "B12", + "B2", + "B3", + "B4", + "B5", + "B6", + "B7", + "B8", + "B9", + "C1", + "C10", + "C11", + "C12", + "C2", + "C3", + "C4", + "C5", + "C6", + "C7", + "C8", + "C9", + "D1", + "D10", + "D11", + "D12", + "D2", + "D3", + "D4", + "D5", + "D6", + "D7", + "D8", + "D9", + "E1", + "E10", + "E11", + "E12", + "E2", + "E3", + "E4", + "E5", + "E6", + "E7", + "E8", + "E9", + "F1", + "F10", + "F11", + "F12", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + "F8", + "F9", + "G1", + "G10", + "G11", + "G12", + "G2", + "G3", + "G4", + "G5", + "G6", + "G7", + "G8", + "G9", + "H1", + "H10", + "H11", + "H12", + "H2", + "H3", + "H4", + "H5", + "H6", + "H7", + "H8", + "H9" + ] + } + ], + "metadata": { + "displayCategory": "aluminumBlock", + "displayName": "Opentrons 96 Well Aluminum Block with NEST Well Plate 100 µL", + "displayVolumeUnits": "µL", + "tags": [] + }, + "namespace": "opentrons", + "ordering": [ + [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1" + ], + [ + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10" + ], + [ + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11" + ], + [ + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ], + [ + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2" + ], + [ + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3" + ], + [ + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4" + ], + [ + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5" + ], + [ + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6" + ], + [ + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7" + ], + [ + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8" + ], + [ + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9" + ] + ], + "parameters": { + "format": "96Standard", + "isMagneticModuleCompatible": false, + "isTiprack": false, + "loadName": "opentrons_96_aluminumblock_nest_wellplate_100ul", + "quirks": [ + "gripperIncompatible" + ] + }, + "schemaVersion": 2, + "stackingOffsetWithLabware": {}, + "stackingOffsetWithModule": {}, + "version": 1, + "wells": { + "A1": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 14.38, + "y": 74.2, + "z": 6.42 + }, + "A10": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 95.38, + "y": 74.2, + "z": 6.42 + }, + "A11": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 104.38, + "y": 74.2, + "z": 6.42 + }, + "A12": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 113.38, + "y": 74.2, + "z": 6.42 + }, + "A2": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 23.38, + "y": 74.2, + "z": 6.42 + }, + "A3": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 32.38, + "y": 74.2, + "z": 6.42 + }, + "A4": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 41.38, + "y": 74.2, + "z": 6.42 + }, + "A5": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 50.38, + "y": 74.2, + "z": 6.42 + }, + "A6": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 59.38, + "y": 74.2, + "z": 6.42 + }, + "A7": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 68.38, + "y": 74.2, + "z": 6.42 + }, + "A8": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 77.38, + "y": 74.2, + "z": 6.42 + }, + "A9": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 86.38, + "y": 74.2, + "z": 6.42 + }, + "B1": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 14.38, + "y": 65.2, + "z": 6.42 + }, + "B10": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 95.38, + "y": 65.2, + "z": 6.42 + }, + "B11": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 104.38, + "y": 65.2, + "z": 6.42 + }, + "B12": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 113.38, + "y": 65.2, + "z": 6.42 + }, + "B2": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 23.38, + "y": 65.2, + "z": 6.42 + }, + "B3": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 32.38, + "y": 65.2, + "z": 6.42 + }, + "B4": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 41.38, + "y": 65.2, + "z": 6.42 + }, + "B5": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 50.38, + "y": 65.2, + "z": 6.42 + }, + "B6": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 59.38, + "y": 65.2, + "z": 6.42 + }, + "B7": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 68.38, + "y": 65.2, + "z": 6.42 + }, + "B8": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 77.38, + "y": 65.2, + "z": 6.42 + }, + "B9": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 86.38, + "y": 65.2, + "z": 6.42 + }, + "C1": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 14.38, + "y": 56.2, + "z": 6.42 + }, + "C10": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 95.38, + "y": 56.2, + "z": 6.42 + }, + "C11": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 104.38, + "y": 56.2, + "z": 6.42 + }, + "C12": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 113.38, + "y": 56.2, + "z": 6.42 + }, + "C2": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 23.38, + "y": 56.2, + "z": 6.42 + }, + "C3": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 32.38, + "y": 56.2, + "z": 6.42 + }, + "C4": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 41.38, + "y": 56.2, + "z": 6.42 + }, + "C5": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 50.38, + "y": 56.2, + "z": 6.42 + }, + "C6": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 59.38, + "y": 56.2, + "z": 6.42 + }, + "C7": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 68.38, + "y": 56.2, + "z": 6.42 + }, + "C8": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 77.38, + "y": 56.2, + "z": 6.42 + }, + "C9": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 86.38, + "y": 56.2, + "z": 6.42 + }, + "D1": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 14.38, + "y": 47.2, + "z": 6.42 + }, + "D10": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 95.38, + "y": 47.2, + "z": 6.42 + }, + "D11": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 104.38, + "y": 47.2, + "z": 6.42 + }, + "D12": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 113.38, + "y": 47.2, + "z": 6.42 + }, + "D2": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 23.38, + "y": 47.2, + "z": 6.42 + }, + "D3": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 32.38, + "y": 47.2, + "z": 6.42 + }, + "D4": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 41.38, + "y": 47.2, + "z": 6.42 + }, + "D5": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 50.38, + "y": 47.2, + "z": 6.42 + }, + "D6": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 59.38, + "y": 47.2, + "z": 6.42 + }, + "D7": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 68.38, + "y": 47.2, + "z": 6.42 + }, + "D8": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 77.38, + "y": 47.2, + "z": 6.42 + }, + "D9": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 86.38, + "y": 47.2, + "z": 6.42 + }, + "E1": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 14.38, + "y": 38.2, + "z": 6.42 + }, + "E10": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 95.38, + "y": 38.2, + "z": 6.42 + }, + "E11": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 104.38, + "y": 38.2, + "z": 6.42 + }, + "E12": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 113.38, + "y": 38.2, + "z": 6.42 + }, + "E2": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 23.38, + "y": 38.2, + "z": 6.42 + }, + "E3": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 32.38, + "y": 38.2, + "z": 6.42 + }, + "E4": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 41.38, + "y": 38.2, + "z": 6.42 + }, + "E5": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 50.38, + "y": 38.2, + "z": 6.42 + }, + "E6": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 59.38, + "y": 38.2, + "z": 6.42 + }, + "E7": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 68.38, + "y": 38.2, + "z": 6.42 + }, + "E8": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 77.38, + "y": 38.2, + "z": 6.42 + }, + "E9": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 86.38, + "y": 38.2, + "z": 6.42 + }, + "F1": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 14.38, + "y": 29.2, + "z": 6.42 + }, + "F10": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 95.38, + "y": 29.2, + "z": 6.42 + }, + "F11": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 104.38, + "y": 29.2, + "z": 6.42 + }, + "F12": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 113.38, + "y": 29.2, + "z": 6.42 + }, + "F2": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 23.38, + "y": 29.2, + "z": 6.42 + }, + "F3": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 32.38, + "y": 29.2, + "z": 6.42 + }, + "F4": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 41.38, + "y": 29.2, + "z": 6.42 + }, + "F5": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 50.38, + "y": 29.2, + "z": 6.42 + }, + "F6": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 59.38, + "y": 29.2, + "z": 6.42 + }, + "F7": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 68.38, + "y": 29.2, + "z": 6.42 + }, + "F8": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 77.38, + "y": 29.2, + "z": 6.42 + }, + "F9": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 86.38, + "y": 29.2, + "z": 6.42 + }, + "G1": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 14.38, + "y": 20.2, + "z": 6.42 + }, + "G10": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 95.38, + "y": 20.2, + "z": 6.42 + }, + "G11": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 104.38, + "y": 20.2, + "z": 6.42 + }, + "G12": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 113.38, + "y": 20.2, + "z": 6.42 + }, + "G2": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 23.38, + "y": 20.2, + "z": 6.42 + }, + "G3": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 32.38, + "y": 20.2, + "z": 6.42 + }, + "G4": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 41.38, + "y": 20.2, + "z": 6.42 + }, + "G5": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 50.38, + "y": 20.2, + "z": 6.42 + }, + "G6": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 59.38, + "y": 20.2, + "z": 6.42 + }, + "G7": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 68.38, + "y": 20.2, + "z": 6.42 + }, + "G8": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 77.38, + "y": 20.2, + "z": 6.42 + }, + "G9": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 86.38, + "y": 20.2, + "z": 6.42 + }, + "H1": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 14.38, + "y": 11.2, + "z": 6.42 + }, + "H10": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 95.38, + "y": 11.2, + "z": 6.42 + }, + "H11": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 104.38, + "y": 11.2, + "z": 6.42 + }, + "H12": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 113.38, + "y": 11.2, + "z": 6.42 + }, + "H2": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 23.38, + "y": 11.2, + "z": 6.42 + }, + "H3": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 32.38, + "y": 11.2, + "z": 6.42 + }, + "H4": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 41.38, + "y": 11.2, + "z": 6.42 + }, + "H5": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 50.38, + "y": 11.2, + "z": 6.42 + }, + "H6": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 59.38, + "y": 11.2, + "z": 6.42 + }, + "H7": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 68.38, + "y": 11.2, + "z": 6.42 + }, + "H8": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 77.38, + "y": 11.2, + "z": 6.42 + }, + "H9": { + "depth": 14.78, + "diameter": 5.34, + "shape": "circular", + "totalLiquidVolume": 100, + "x": 86.38, + "y": 11.2, + "z": 6.42 + } + } + } + }, + "status": "succeeded" + }, + { + "commandType": "loadLabware", + "notes": [], + "params": { + "displayName": "Liquid Waste", + "loadName": "nest_1_reservoir_195ml", + "location": { + "slotName": "9" + }, + "namespace": "opentrons", + "version": 1 + }, + "result": { + "definition": { + "allowedRoles": [], + "brand": { + "brand": "NEST", + "brandId": [ + "360103" + ], + "links": [ + "https://www.nest-biotech.com/reagent-reserviors/59178416.html" + ] + }, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + }, + "dimensions": { + "xDimension": 127.76, + "yDimension": 85.48, + "zDimension": 31.4 + }, + "gripperOffsets": {}, + "groups": [ + { + "metadata": { + "wellBottomShape": "v" + }, + "wells": [ + "A1" + ] + } + ], + "metadata": { + "displayCategory": "reservoir", + "displayName": "NEST 1 Well Reservoir 195 mL", + "displayVolumeUnits": "mL", + "tags": [] + }, + "namespace": "opentrons", + "ordering": [ + [ + "A1" + ] + ], + "parameters": { + "format": "trough", + "isMagneticModuleCompatible": false, + "isTiprack": false, + "loadName": "nest_1_reservoir_195ml", + "quirks": [ + "centerMultichannelOnWells", + "touchTipDisabled" + ] + }, + "schemaVersion": 2, + "stackingOffsetWithLabware": {}, + "stackingOffsetWithModule": {}, + "version": 1, + "wells": { + "A1": { + "depth": 25, + "shape": "rectangular", + "totalLiquidVolume": 195000, + "x": 63.88, + "xDimension": 106.8, + "y": 42.74, + "yDimension": 71.2, + "z": 4.55 + } + } + } + }, + "status": "succeeded" + }, + { + "commandType": "loadLabware", + "notes": [], + "params": { + "displayName": "reagent reservoir 2", + "loadName": "nest_12_reservoir_15ml", + "location": { + "slotName": "3" + }, + "namespace": "opentrons", + "version": 1 + }, + "result": { + "definition": { + "allowedRoles": [], + "brand": { + "brand": "NEST", + "brandId": [ + "360102" + ], + "links": [ + "https://www.nest-biotech.com/reagent-reserviors/59178414.html" + ] + }, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + }, + "dimensions": { + "xDimension": 127.76, + "yDimension": 85.48, + "zDimension": 31.4 + }, + "gripperOffsets": {}, + "groups": [ + { + "metadata": { + "wellBottomShape": "v" + }, + "wells": [ + "A1", + "A10", + "A11", + "A12", + "A2", + "A3", + "A4", + "A5", + "A6", + "A7", + "A8", + "A9" + ] + } + ], + "metadata": { + "displayCategory": "reservoir", + "displayName": "NEST 12 Well Reservoir 15 mL", + "displayVolumeUnits": "mL", + "tags": [] + }, + "namespace": "opentrons", + "ordering": [ + [ + "A1" + ], + [ + "A10" + ], + [ + "A11" + ], + [ + "A12" + ], + [ + "A2" + ], + [ + "A3" + ], + [ + "A4" + ], + [ + "A5" + ], + [ + "A6" + ], + [ + "A7" + ], + [ + "A8" + ], + [ + "A9" + ] + ], + "parameters": { + "format": "trough", + "isMagneticModuleCompatible": false, + "isTiprack": false, + "loadName": "nest_12_reservoir_15ml", + "quirks": [ + "centerMultichannelOnWells", + "touchTipDisabled" + ] + }, + "schemaVersion": 2, + "stackingOffsetWithLabware": {}, + "stackingOffsetWithModule": {}, + "version": 1, + "wells": { + "A1": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 14.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + }, + "A10": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 95.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + }, + "A11": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 104.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + }, + "A12": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 113.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + }, + "A2": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 23.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + }, + "A3": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 32.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + }, + "A4": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 41.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + }, + "A5": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 50.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + }, + "A6": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 59.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + }, + "A7": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 68.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + }, + "A8": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 77.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + }, + "A9": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 86.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + } + } + } + }, + "status": "succeeded" + }, + { + "commandType": "loadLabware", + "notes": [], + "params": { + "displayName": "reagent reservoir 1", + "loadName": "nest_12_reservoir_15ml", + "location": { + "slotName": "2" + }, + "namespace": "opentrons", + "version": 1 + }, + "result": { + "definition": { + "allowedRoles": [], + "brand": { + "brand": "NEST", + "brandId": [ + "360102" + ], + "links": [ + "https://www.nest-biotech.com/reagent-reserviors/59178414.html" + ] + }, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + }, + "dimensions": { + "xDimension": 127.76, + "yDimension": 85.48, + "zDimension": 31.4 + }, + "gripperOffsets": {}, + "groups": [ + { + "metadata": { + "wellBottomShape": "v" + }, + "wells": [ + "A1", + "A10", + "A11", + "A12", + "A2", + "A3", + "A4", + "A5", + "A6", + "A7", + "A8", + "A9" + ] + } + ], + "metadata": { + "displayCategory": "reservoir", + "displayName": "NEST 12 Well Reservoir 15 mL", + "displayVolumeUnits": "mL", + "tags": [] + }, + "namespace": "opentrons", + "ordering": [ + [ + "A1" + ], + [ + "A10" + ], + [ + "A11" + ], + [ + "A12" + ], + [ + "A2" + ], + [ + "A3" + ], + [ + "A4" + ], + [ + "A5" + ], + [ + "A6" + ], + [ + "A7" + ], + [ + "A8" + ], + [ + "A9" + ] + ], + "parameters": { + "format": "trough", + "isMagneticModuleCompatible": false, + "isTiprack": false, + "loadName": "nest_12_reservoir_15ml", + "quirks": [ + "centerMultichannelOnWells", + "touchTipDisabled" + ] + }, + "schemaVersion": 2, + "stackingOffsetWithLabware": {}, + "stackingOffsetWithModule": {}, + "version": 1, + "wells": { + "A1": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 14.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + }, + "A10": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 95.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + }, + "A11": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 104.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + }, + "A12": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 113.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + }, + "A2": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 23.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + }, + "A3": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 32.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + }, + "A4": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 41.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + }, + "A5": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 50.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + }, + "A6": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 59.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + }, + "A7": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 68.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + }, + "A8": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 77.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + }, + "A9": { + "depth": 26.85, + "shape": "rectangular", + "totalLiquidVolume": 15000, + "x": 86.38, + "xDimension": 8.2, + "y": 42.78, + "yDimension": 71.2, + "z": 4.55 + } + } + } + }, + "status": "succeeded" + }, + { + "commandType": "loadLabware", + "notes": [], + "params": { + "displayName": "200µl filtertiprack", + "loadName": "opentrons_96_tiprack_300ul", + "location": { + "slotName": "5" + }, + "namespace": "opentrons", + "version": 1 + }, + "result": { + "definition": { + "allowedRoles": [], + "brand": { + "brand": "Opentrons", + "brandId": [], + "links": [ + "https://shop.opentrons.com/collections/opentrons-tips/products/opentrons-300ul-tips" + ] + }, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + }, + "dimensions": { + "xDimension": 127.76, + "yDimension": 85.48, + "zDimension": 64.49 + }, + "gripperOffsets": {}, + "groups": [ + { + "metadata": {}, + "wells": [ + "A1", + "A10", + "A11", + "A12", + "A2", + "A3", + "A4", + "A5", + "A6", + "A7", + "A8", + "A9", + "B1", + "B10", + "B11", + "B12", + "B2", + "B3", + "B4", + "B5", + "B6", + "B7", + "B8", + "B9", + "C1", + "C10", + "C11", + "C12", + "C2", + "C3", + "C4", + "C5", + "C6", + "C7", + "C8", + "C9", + "D1", + "D10", + "D11", + "D12", + "D2", + "D3", + "D4", + "D5", + "D6", + "D7", + "D8", + "D9", + "E1", + "E10", + "E11", + "E12", + "E2", + "E3", + "E4", + "E5", + "E6", + "E7", + "E8", + "E9", + "F1", + "F10", + "F11", + "F12", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + "F8", + "F9", + "G1", + "G10", + "G11", + "G12", + "G2", + "G3", + "G4", + "G5", + "G6", + "G7", + "G8", + "G9", + "H1", + "H10", + "H11", + "H12", + "H2", + "H3", + "H4", + "H5", + "H6", + "H7", + "H8", + "H9" + ] + } + ], + "metadata": { + "displayCategory": "tipRack", + "displayName": "Opentrons OT-2 96 Tip Rack 300 µL", + "displayVolumeUnits": "µL", + "tags": [] + }, + "namespace": "opentrons", + "ordering": [ + [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1" + ], + [ + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10" + ], + [ + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11" + ], + [ + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ], + [ + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2" + ], + [ + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3" + ], + [ + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4" + ], + [ + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5" + ], + [ + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6" + ], + [ + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7" + ], + [ + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8" + ], + [ + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9" + ] + ], + "parameters": { + "format": "96Standard", + "isMagneticModuleCompatible": false, + "isTiprack": true, + "loadName": "opentrons_96_tiprack_300ul", + "tipLength": 59.3, + "tipOverlap": 7.47 + }, + "schemaVersion": 2, + "stackingOffsetWithLabware": {}, + "stackingOffsetWithModule": {}, + "version": 1, + "wells": { + "A1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 74.24, + "z": 5.39 + }, + "A10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 74.24, + "z": 5.39 + }, + "A11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 74.24, + "z": 5.39 + }, + "A12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 74.24, + "z": 5.39 + }, + "A2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 74.24, + "z": 5.39 + }, + "A3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 74.24, + "z": 5.39 + }, + "A4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 74.24, + "z": 5.39 + }, + "A5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 74.24, + "z": 5.39 + }, + "A6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 74.24, + "z": 5.39 + }, + "A7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 74.24, + "z": 5.39 + }, + "A8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 74.24, + "z": 5.39 + }, + "A9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 74.24, + "z": 5.39 + }, + "B1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 65.24, + "z": 5.39 + }, + "B10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 65.24, + "z": 5.39 + }, + "B11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 65.24, + "z": 5.39 + }, + "B12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 65.24, + "z": 5.39 + }, + "B2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 65.24, + "z": 5.39 + }, + "B3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 65.24, + "z": 5.39 + }, + "B4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 65.24, + "z": 5.39 + }, + "B5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 65.24, + "z": 5.39 + }, + "B6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 65.24, + "z": 5.39 + }, + "B7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 65.24, + "z": 5.39 + }, + "B8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 65.24, + "z": 5.39 + }, + "B9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 65.24, + "z": 5.39 + }, + "C1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 56.24, + "z": 5.39 + }, + "C10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 56.24, + "z": 5.39 + }, + "C11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 56.24, + "z": 5.39 + }, + "C12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 56.24, + "z": 5.39 + }, + "C2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 56.24, + "z": 5.39 + }, + "C3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 56.24, + "z": 5.39 + }, + "C4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 56.24, + "z": 5.39 + }, + "C5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 56.24, + "z": 5.39 + }, + "C6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 56.24, + "z": 5.39 + }, + "C7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 56.24, + "z": 5.39 + }, + "C8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 56.24, + "z": 5.39 + }, + "C9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 56.24, + "z": 5.39 + }, + "D1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 47.24, + "z": 5.39 + }, + "D10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 47.24, + "z": 5.39 + }, + "D11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 47.24, + "z": 5.39 + }, + "D12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 47.24, + "z": 5.39 + }, + "D2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 47.24, + "z": 5.39 + }, + "D3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 47.24, + "z": 5.39 + }, + "D4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 47.24, + "z": 5.39 + }, + "D5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 47.24, + "z": 5.39 + }, + "D6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 47.24, + "z": 5.39 + }, + "D7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 47.24, + "z": 5.39 + }, + "D8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 47.24, + "z": 5.39 + }, + "D9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 47.24, + "z": 5.39 + }, + "E1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 38.24, + "z": 5.39 + }, + "E10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 38.24, + "z": 5.39 + }, + "E11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 38.24, + "z": 5.39 + }, + "E12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 38.24, + "z": 5.39 + }, + "E2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 38.24, + "z": 5.39 + }, + "E3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 38.24, + "z": 5.39 + }, + "E4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 38.24, + "z": 5.39 + }, + "E5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 38.24, + "z": 5.39 + }, + "E6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 38.24, + "z": 5.39 + }, + "E7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 38.24, + "z": 5.39 + }, + "E8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 38.24, + "z": 5.39 + }, + "E9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 38.24, + "z": 5.39 + }, + "F1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 29.24, + "z": 5.39 + }, + "F10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 29.24, + "z": 5.39 + }, + "F11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 29.24, + "z": 5.39 + }, + "F12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 29.24, + "z": 5.39 + }, + "F2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 29.24, + "z": 5.39 + }, + "F3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 29.24, + "z": 5.39 + }, + "F4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 29.24, + "z": 5.39 + }, + "F5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 29.24, + "z": 5.39 + }, + "F6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 29.24, + "z": 5.39 + }, + "F7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 29.24, + "z": 5.39 + }, + "F8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 29.24, + "z": 5.39 + }, + "F9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 29.24, + "z": 5.39 + }, + "G1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 20.24, + "z": 5.39 + }, + "G10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 20.24, + "z": 5.39 + }, + "G11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 20.24, + "z": 5.39 + }, + "G12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 20.24, + "z": 5.39 + }, + "G2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 20.24, + "z": 5.39 + }, + "G3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 20.24, + "z": 5.39 + }, + "G4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 20.24, + "z": 5.39 + }, + "G5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 20.24, + "z": 5.39 + }, + "G6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 20.24, + "z": 5.39 + }, + "G7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 20.24, + "z": 5.39 + }, + "G8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 20.24, + "z": 5.39 + }, + "G9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 20.24, + "z": 5.39 + }, + "H1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 11.24, + "z": 5.39 + }, + "H10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 11.24, + "z": 5.39 + }, + "H11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 11.24, + "z": 5.39 + }, + "H12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 11.24, + "z": 5.39 + }, + "H2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 11.24, + "z": 5.39 + }, + "H3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 11.24, + "z": 5.39 + }, + "H4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 11.24, + "z": 5.39 + }, + "H5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 11.24, + "z": 5.39 + }, + "H6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 11.24, + "z": 5.39 + }, + "H7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 11.24, + "z": 5.39 + }, + "H8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 11.24, + "z": 5.39 + }, + "H9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 11.24, + "z": 5.39 + } + } + } + }, + "status": "succeeded" + }, + { + "commandType": "loadLabware", + "notes": [], + "params": { + "displayName": "200µl filtertiprack", + "loadName": "opentrons_96_tiprack_300ul", + "location": { + "slotName": "7" + }, + "namespace": "opentrons", + "version": 1 + }, + "result": { + "definition": { + "allowedRoles": [], + "brand": { + "brand": "Opentrons", + "brandId": [], + "links": [ + "https://shop.opentrons.com/collections/opentrons-tips/products/opentrons-300ul-tips" + ] + }, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + }, + "dimensions": { + "xDimension": 127.76, + "yDimension": 85.48, + "zDimension": 64.49 + }, + "gripperOffsets": {}, + "groups": [ + { + "metadata": {}, + "wells": [ + "A1", + "A10", + "A11", + "A12", + "A2", + "A3", + "A4", + "A5", + "A6", + "A7", + "A8", + "A9", + "B1", + "B10", + "B11", + "B12", + "B2", + "B3", + "B4", + "B5", + "B6", + "B7", + "B8", + "B9", + "C1", + "C10", + "C11", + "C12", + "C2", + "C3", + "C4", + "C5", + "C6", + "C7", + "C8", + "C9", + "D1", + "D10", + "D11", + "D12", + "D2", + "D3", + "D4", + "D5", + "D6", + "D7", + "D8", + "D9", + "E1", + "E10", + "E11", + "E12", + "E2", + "E3", + "E4", + "E5", + "E6", + "E7", + "E8", + "E9", + "F1", + "F10", + "F11", + "F12", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + "F8", + "F9", + "G1", + "G10", + "G11", + "G12", + "G2", + "G3", + "G4", + "G5", + "G6", + "G7", + "G8", + "G9", + "H1", + "H10", + "H11", + "H12", + "H2", + "H3", + "H4", + "H5", + "H6", + "H7", + "H8", + "H9" + ] + } + ], + "metadata": { + "displayCategory": "tipRack", + "displayName": "Opentrons OT-2 96 Tip Rack 300 µL", + "displayVolumeUnits": "µL", + "tags": [] + }, + "namespace": "opentrons", + "ordering": [ + [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1" + ], + [ + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10" + ], + [ + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11" + ], + [ + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ], + [ + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2" + ], + [ + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3" + ], + [ + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4" + ], + [ + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5" + ], + [ + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6" + ], + [ + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7" + ], + [ + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8" + ], + [ + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9" + ] + ], + "parameters": { + "format": "96Standard", + "isMagneticModuleCompatible": false, + "isTiprack": true, + "loadName": "opentrons_96_tiprack_300ul", + "tipLength": 59.3, + "tipOverlap": 7.47 + }, + "schemaVersion": 2, + "stackingOffsetWithLabware": {}, + "stackingOffsetWithModule": {}, + "version": 1, + "wells": { + "A1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 74.24, + "z": 5.39 + }, + "A10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 74.24, + "z": 5.39 + }, + "A11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 74.24, + "z": 5.39 + }, + "A12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 74.24, + "z": 5.39 + }, + "A2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 74.24, + "z": 5.39 + }, + "A3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 74.24, + "z": 5.39 + }, + "A4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 74.24, + "z": 5.39 + }, + "A5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 74.24, + "z": 5.39 + }, + "A6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 74.24, + "z": 5.39 + }, + "A7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 74.24, + "z": 5.39 + }, + "A8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 74.24, + "z": 5.39 + }, + "A9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 74.24, + "z": 5.39 + }, + "B1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 65.24, + "z": 5.39 + }, + "B10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 65.24, + "z": 5.39 + }, + "B11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 65.24, + "z": 5.39 + }, + "B12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 65.24, + "z": 5.39 + }, + "B2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 65.24, + "z": 5.39 + }, + "B3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 65.24, + "z": 5.39 + }, + "B4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 65.24, + "z": 5.39 + }, + "B5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 65.24, + "z": 5.39 + }, + "B6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 65.24, + "z": 5.39 + }, + "B7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 65.24, + "z": 5.39 + }, + "B8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 65.24, + "z": 5.39 + }, + "B9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 65.24, + "z": 5.39 + }, + "C1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 56.24, + "z": 5.39 + }, + "C10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 56.24, + "z": 5.39 + }, + "C11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 56.24, + "z": 5.39 + }, + "C12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 56.24, + "z": 5.39 + }, + "C2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 56.24, + "z": 5.39 + }, + "C3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 56.24, + "z": 5.39 + }, + "C4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 56.24, + "z": 5.39 + }, + "C5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 56.24, + "z": 5.39 + }, + "C6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 56.24, + "z": 5.39 + }, + "C7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 56.24, + "z": 5.39 + }, + "C8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 56.24, + "z": 5.39 + }, + "C9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 56.24, + "z": 5.39 + }, + "D1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 47.24, + "z": 5.39 + }, + "D10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 47.24, + "z": 5.39 + }, + "D11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 47.24, + "z": 5.39 + }, + "D12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 47.24, + "z": 5.39 + }, + "D2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 47.24, + "z": 5.39 + }, + "D3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 47.24, + "z": 5.39 + }, + "D4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 47.24, + "z": 5.39 + }, + "D5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 47.24, + "z": 5.39 + }, + "D6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 47.24, + "z": 5.39 + }, + "D7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 47.24, + "z": 5.39 + }, + "D8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 47.24, + "z": 5.39 + }, + "D9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 47.24, + "z": 5.39 + }, + "E1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 38.24, + "z": 5.39 + }, + "E10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 38.24, + "z": 5.39 + }, + "E11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 38.24, + "z": 5.39 + }, + "E12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 38.24, + "z": 5.39 + }, + "E2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 38.24, + "z": 5.39 + }, + "E3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 38.24, + "z": 5.39 + }, + "E4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 38.24, + "z": 5.39 + }, + "E5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 38.24, + "z": 5.39 + }, + "E6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 38.24, + "z": 5.39 + }, + "E7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 38.24, + "z": 5.39 + }, + "E8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 38.24, + "z": 5.39 + }, + "E9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 38.24, + "z": 5.39 + }, + "F1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 29.24, + "z": 5.39 + }, + "F10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 29.24, + "z": 5.39 + }, + "F11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 29.24, + "z": 5.39 + }, + "F12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 29.24, + "z": 5.39 + }, + "F2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 29.24, + "z": 5.39 + }, + "F3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 29.24, + "z": 5.39 + }, + "F4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 29.24, + "z": 5.39 + }, + "F5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 29.24, + "z": 5.39 + }, + "F6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 29.24, + "z": 5.39 + }, + "F7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 29.24, + "z": 5.39 + }, + "F8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 29.24, + "z": 5.39 + }, + "F9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 29.24, + "z": 5.39 + }, + "G1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 20.24, + "z": 5.39 + }, + "G10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 20.24, + "z": 5.39 + }, + "G11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 20.24, + "z": 5.39 + }, + "G12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 20.24, + "z": 5.39 + }, + "G2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 20.24, + "z": 5.39 + }, + "G3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 20.24, + "z": 5.39 + }, + "G4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 20.24, + "z": 5.39 + }, + "G5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 20.24, + "z": 5.39 + }, + "G6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 20.24, + "z": 5.39 + }, + "G7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 20.24, + "z": 5.39 + }, + "G8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 20.24, + "z": 5.39 + }, + "G9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 20.24, + "z": 5.39 + }, + "H1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 11.24, + "z": 5.39 + }, + "H10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 11.24, + "z": 5.39 + }, + "H11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 11.24, + "z": 5.39 + }, + "H12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 11.24, + "z": 5.39 + }, + "H2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 11.24, + "z": 5.39 + }, + "H3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 11.24, + "z": 5.39 + }, + "H4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 11.24, + "z": 5.39 + }, + "H5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 11.24, + "z": 5.39 + }, + "H6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 11.24, + "z": 5.39 + }, + "H7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 11.24, + "z": 5.39 + }, + "H8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 11.24, + "z": 5.39 + }, + "H9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 11.24, + "z": 5.39 + } + } + } + }, + "status": "succeeded" + }, + { + "commandType": "loadLabware", + "notes": [], + "params": { + "displayName": "200µl filtertiprack", + "loadName": "opentrons_96_tiprack_300ul", + "location": { + "slotName": "8" + }, + "namespace": "opentrons", + "version": 1 + }, + "result": { + "definition": { + "allowedRoles": [], + "brand": { + "brand": "Opentrons", + "brandId": [], + "links": [ + "https://shop.opentrons.com/collections/opentrons-tips/products/opentrons-300ul-tips" + ] + }, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + }, + "dimensions": { + "xDimension": 127.76, + "yDimension": 85.48, + "zDimension": 64.49 + }, + "gripperOffsets": {}, + "groups": [ + { + "metadata": {}, + "wells": [ + "A1", + "A10", + "A11", + "A12", + "A2", + "A3", + "A4", + "A5", + "A6", + "A7", + "A8", + "A9", + "B1", + "B10", + "B11", + "B12", + "B2", + "B3", + "B4", + "B5", + "B6", + "B7", + "B8", + "B9", + "C1", + "C10", + "C11", + "C12", + "C2", + "C3", + "C4", + "C5", + "C6", + "C7", + "C8", + "C9", + "D1", + "D10", + "D11", + "D12", + "D2", + "D3", + "D4", + "D5", + "D6", + "D7", + "D8", + "D9", + "E1", + "E10", + "E11", + "E12", + "E2", + "E3", + "E4", + "E5", + "E6", + "E7", + "E8", + "E9", + "F1", + "F10", + "F11", + "F12", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + "F8", + "F9", + "G1", + "G10", + "G11", + "G12", + "G2", + "G3", + "G4", + "G5", + "G6", + "G7", + "G8", + "G9", + "H1", + "H10", + "H11", + "H12", + "H2", + "H3", + "H4", + "H5", + "H6", + "H7", + "H8", + "H9" + ] + } + ], + "metadata": { + "displayCategory": "tipRack", + "displayName": "Opentrons OT-2 96 Tip Rack 300 µL", + "displayVolumeUnits": "µL", + "tags": [] + }, + "namespace": "opentrons", + "ordering": [ + [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1" + ], + [ + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10" + ], + [ + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11" + ], + [ + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ], + [ + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2" + ], + [ + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3" + ], + [ + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4" + ], + [ + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5" + ], + [ + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6" + ], + [ + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7" + ], + [ + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8" + ], + [ + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9" + ] + ], + "parameters": { + "format": "96Standard", + "isMagneticModuleCompatible": false, + "isTiprack": true, + "loadName": "opentrons_96_tiprack_300ul", + "tipLength": 59.3, + "tipOverlap": 7.47 + }, + "schemaVersion": 2, + "stackingOffsetWithLabware": {}, + "stackingOffsetWithModule": {}, + "version": 1, + "wells": { + "A1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 74.24, + "z": 5.39 + }, + "A10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 74.24, + "z": 5.39 + }, + "A11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 74.24, + "z": 5.39 + }, + "A12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 74.24, + "z": 5.39 + }, + "A2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 74.24, + "z": 5.39 + }, + "A3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 74.24, + "z": 5.39 + }, + "A4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 74.24, + "z": 5.39 + }, + "A5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 74.24, + "z": 5.39 + }, + "A6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 74.24, + "z": 5.39 + }, + "A7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 74.24, + "z": 5.39 + }, + "A8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 74.24, + "z": 5.39 + }, + "A9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 74.24, + "z": 5.39 + }, + "B1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 65.24, + "z": 5.39 + }, + "B10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 65.24, + "z": 5.39 + }, + "B11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 65.24, + "z": 5.39 + }, + "B12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 65.24, + "z": 5.39 + }, + "B2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 65.24, + "z": 5.39 + }, + "B3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 65.24, + "z": 5.39 + }, + "B4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 65.24, + "z": 5.39 + }, + "B5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 65.24, + "z": 5.39 + }, + "B6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 65.24, + "z": 5.39 + }, + "B7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 65.24, + "z": 5.39 + }, + "B8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 65.24, + "z": 5.39 + }, + "B9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 65.24, + "z": 5.39 + }, + "C1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 56.24, + "z": 5.39 + }, + "C10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 56.24, + "z": 5.39 + }, + "C11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 56.24, + "z": 5.39 + }, + "C12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 56.24, + "z": 5.39 + }, + "C2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 56.24, + "z": 5.39 + }, + "C3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 56.24, + "z": 5.39 + }, + "C4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 56.24, + "z": 5.39 + }, + "C5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 56.24, + "z": 5.39 + }, + "C6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 56.24, + "z": 5.39 + }, + "C7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 56.24, + "z": 5.39 + }, + "C8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 56.24, + "z": 5.39 + }, + "C9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 56.24, + "z": 5.39 + }, + "D1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 47.24, + "z": 5.39 + }, + "D10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 47.24, + "z": 5.39 + }, + "D11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 47.24, + "z": 5.39 + }, + "D12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 47.24, + "z": 5.39 + }, + "D2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 47.24, + "z": 5.39 + }, + "D3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 47.24, + "z": 5.39 + }, + "D4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 47.24, + "z": 5.39 + }, + "D5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 47.24, + "z": 5.39 + }, + "D6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 47.24, + "z": 5.39 + }, + "D7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 47.24, + "z": 5.39 + }, + "D8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 47.24, + "z": 5.39 + }, + "D9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 47.24, + "z": 5.39 + }, + "E1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 38.24, + "z": 5.39 + }, + "E10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 38.24, + "z": 5.39 + }, + "E11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 38.24, + "z": 5.39 + }, + "E12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 38.24, + "z": 5.39 + }, + "E2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 38.24, + "z": 5.39 + }, + "E3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 38.24, + "z": 5.39 + }, + "E4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 38.24, + "z": 5.39 + }, + "E5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 38.24, + "z": 5.39 + }, + "E6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 38.24, + "z": 5.39 + }, + "E7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 38.24, + "z": 5.39 + }, + "E8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 38.24, + "z": 5.39 + }, + "E9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 38.24, + "z": 5.39 + }, + "F1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 29.24, + "z": 5.39 + }, + "F10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 29.24, + "z": 5.39 + }, + "F11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 29.24, + "z": 5.39 + }, + "F12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 29.24, + "z": 5.39 + }, + "F2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 29.24, + "z": 5.39 + }, + "F3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 29.24, + "z": 5.39 + }, + "F4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 29.24, + "z": 5.39 + }, + "F5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 29.24, + "z": 5.39 + }, + "F6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 29.24, + "z": 5.39 + }, + "F7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 29.24, + "z": 5.39 + }, + "F8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 29.24, + "z": 5.39 + }, + "F9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 29.24, + "z": 5.39 + }, + "G1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 20.24, + "z": 5.39 + }, + "G10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 20.24, + "z": 5.39 + }, + "G11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 20.24, + "z": 5.39 + }, + "G12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 20.24, + "z": 5.39 + }, + "G2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 20.24, + "z": 5.39 + }, + "G3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 20.24, + "z": 5.39 + }, + "G4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 20.24, + "z": 5.39 + }, + "G5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 20.24, + "z": 5.39 + }, + "G6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 20.24, + "z": 5.39 + }, + "G7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 20.24, + "z": 5.39 + }, + "G8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 20.24, + "z": 5.39 + }, + "G9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 20.24, + "z": 5.39 + }, + "H1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 11.24, + "z": 5.39 + }, + "H10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 11.24, + "z": 5.39 + }, + "H11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 11.24, + "z": 5.39 + }, + "H12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 11.24, + "z": 5.39 + }, + "H2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 11.24, + "z": 5.39 + }, + "H3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 11.24, + "z": 5.39 + }, + "H4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 11.24, + "z": 5.39 + }, + "H5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 11.24, + "z": 5.39 + }, + "H6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 11.24, + "z": 5.39 + }, + "H7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 11.24, + "z": 5.39 + }, + "H8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 11.24, + "z": 5.39 + }, + "H9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 11.24, + "z": 5.39 + } + } + } + }, + "status": "succeeded" + }, + { + "commandType": "loadLabware", + "notes": [], + "params": { + "displayName": "200µl filtertiprack", + "loadName": "opentrons_96_tiprack_300ul", + "location": { + "slotName": "10" + }, + "namespace": "opentrons", + "version": 1 + }, + "result": { + "definition": { + "allowedRoles": [], + "brand": { + "brand": "Opentrons", + "brandId": [], + "links": [ + "https://shop.opentrons.com/collections/opentrons-tips/products/opentrons-300ul-tips" + ] + }, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + }, + "dimensions": { + "xDimension": 127.76, + "yDimension": 85.48, + "zDimension": 64.49 + }, + "gripperOffsets": {}, + "groups": [ + { + "metadata": {}, + "wells": [ + "A1", + "A10", + "A11", + "A12", + "A2", + "A3", + "A4", + "A5", + "A6", + "A7", + "A8", + "A9", + "B1", + "B10", + "B11", + "B12", + "B2", + "B3", + "B4", + "B5", + "B6", + "B7", + "B8", + "B9", + "C1", + "C10", + "C11", + "C12", + "C2", + "C3", + "C4", + "C5", + "C6", + "C7", + "C8", + "C9", + "D1", + "D10", + "D11", + "D12", + "D2", + "D3", + "D4", + "D5", + "D6", + "D7", + "D8", + "D9", + "E1", + "E10", + "E11", + "E12", + "E2", + "E3", + "E4", + "E5", + "E6", + "E7", + "E8", + "E9", + "F1", + "F10", + "F11", + "F12", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + "F8", + "F9", + "G1", + "G10", + "G11", + "G12", + "G2", + "G3", + "G4", + "G5", + "G6", + "G7", + "G8", + "G9", + "H1", + "H10", + "H11", + "H12", + "H2", + "H3", + "H4", + "H5", + "H6", + "H7", + "H8", + "H9" + ] + } + ], + "metadata": { + "displayCategory": "tipRack", + "displayName": "Opentrons OT-2 96 Tip Rack 300 µL", + "displayVolumeUnits": "µL", + "tags": [] + }, + "namespace": "opentrons", + "ordering": [ + [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1" + ], + [ + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10" + ], + [ + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11" + ], + [ + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ], + [ + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2" + ], + [ + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3" + ], + [ + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4" + ], + [ + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5" + ], + [ + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6" + ], + [ + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7" + ], + [ + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8" + ], + [ + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9" + ] + ], + "parameters": { + "format": "96Standard", + "isMagneticModuleCompatible": false, + "isTiprack": true, + "loadName": "opentrons_96_tiprack_300ul", + "tipLength": 59.3, + "tipOverlap": 7.47 + }, + "schemaVersion": 2, + "stackingOffsetWithLabware": {}, + "stackingOffsetWithModule": {}, + "version": 1, + "wells": { + "A1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 74.24, + "z": 5.39 + }, + "A10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 74.24, + "z": 5.39 + }, + "A11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 74.24, + "z": 5.39 + }, + "A12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 74.24, + "z": 5.39 + }, + "A2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 74.24, + "z": 5.39 + }, + "A3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 74.24, + "z": 5.39 + }, + "A4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 74.24, + "z": 5.39 + }, + "A5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 74.24, + "z": 5.39 + }, + "A6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 74.24, + "z": 5.39 + }, + "A7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 74.24, + "z": 5.39 + }, + "A8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 74.24, + "z": 5.39 + }, + "A9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 74.24, + "z": 5.39 + }, + "B1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 65.24, + "z": 5.39 + }, + "B10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 65.24, + "z": 5.39 + }, + "B11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 65.24, + "z": 5.39 + }, + "B12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 65.24, + "z": 5.39 + }, + "B2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 65.24, + "z": 5.39 + }, + "B3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 65.24, + "z": 5.39 + }, + "B4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 65.24, + "z": 5.39 + }, + "B5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 65.24, + "z": 5.39 + }, + "B6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 65.24, + "z": 5.39 + }, + "B7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 65.24, + "z": 5.39 + }, + "B8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 65.24, + "z": 5.39 + }, + "B9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 65.24, + "z": 5.39 + }, + "C1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 56.24, + "z": 5.39 + }, + "C10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 56.24, + "z": 5.39 + }, + "C11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 56.24, + "z": 5.39 + }, + "C12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 56.24, + "z": 5.39 + }, + "C2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 56.24, + "z": 5.39 + }, + "C3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 56.24, + "z": 5.39 + }, + "C4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 56.24, + "z": 5.39 + }, + "C5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 56.24, + "z": 5.39 + }, + "C6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 56.24, + "z": 5.39 + }, + "C7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 56.24, + "z": 5.39 + }, + "C8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 56.24, + "z": 5.39 + }, + "C9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 56.24, + "z": 5.39 + }, + "D1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 47.24, + "z": 5.39 + }, + "D10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 47.24, + "z": 5.39 + }, + "D11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 47.24, + "z": 5.39 + }, + "D12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 47.24, + "z": 5.39 + }, + "D2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 47.24, + "z": 5.39 + }, + "D3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 47.24, + "z": 5.39 + }, + "D4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 47.24, + "z": 5.39 + }, + "D5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 47.24, + "z": 5.39 + }, + "D6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 47.24, + "z": 5.39 + }, + "D7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 47.24, + "z": 5.39 + }, + "D8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 47.24, + "z": 5.39 + }, + "D9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 47.24, + "z": 5.39 + }, + "E1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 38.24, + "z": 5.39 + }, + "E10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 38.24, + "z": 5.39 + }, + "E11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 38.24, + "z": 5.39 + }, + "E12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 38.24, + "z": 5.39 + }, + "E2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 38.24, + "z": 5.39 + }, + "E3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 38.24, + "z": 5.39 + }, + "E4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 38.24, + "z": 5.39 + }, + "E5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 38.24, + "z": 5.39 + }, + "E6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 38.24, + "z": 5.39 + }, + "E7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 38.24, + "z": 5.39 + }, + "E8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 38.24, + "z": 5.39 + }, + "E9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 38.24, + "z": 5.39 + }, + "F1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 29.24, + "z": 5.39 + }, + "F10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 29.24, + "z": 5.39 + }, + "F11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 29.24, + "z": 5.39 + }, + "F12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 29.24, + "z": 5.39 + }, + "F2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 29.24, + "z": 5.39 + }, + "F3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 29.24, + "z": 5.39 + }, + "F4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 29.24, + "z": 5.39 + }, + "F5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 29.24, + "z": 5.39 + }, + "F6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 29.24, + "z": 5.39 + }, + "F7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 29.24, + "z": 5.39 + }, + "F8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 29.24, + "z": 5.39 + }, + "F9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 29.24, + "z": 5.39 + }, + "G1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 20.24, + "z": 5.39 + }, + "G10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 20.24, + "z": 5.39 + }, + "G11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 20.24, + "z": 5.39 + }, + "G12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 20.24, + "z": 5.39 + }, + "G2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 20.24, + "z": 5.39 + }, + "G3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 20.24, + "z": 5.39 + }, + "G4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 20.24, + "z": 5.39 + }, + "G5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 20.24, + "z": 5.39 + }, + "G6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 20.24, + "z": 5.39 + }, + "G7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 20.24, + "z": 5.39 + }, + "G8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 20.24, + "z": 5.39 + }, + "G9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 20.24, + "z": 5.39 + }, + "H1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 11.24, + "z": 5.39 + }, + "H10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 11.24, + "z": 5.39 + }, + "H11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 11.24, + "z": 5.39 + }, + "H12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 11.24, + "z": 5.39 + }, + "H2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 11.24, + "z": 5.39 + }, + "H3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 11.24, + "z": 5.39 + }, + "H4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 11.24, + "z": 5.39 + }, + "H5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 11.24, + "z": 5.39 + }, + "H6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 11.24, + "z": 5.39 + }, + "H7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 11.24, + "z": 5.39 + }, + "H8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 11.24, + "z": 5.39 + }, + "H9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 11.24, + "z": 5.39 + } + } + } + }, + "status": "succeeded" + }, + { + "commandType": "loadLabware", + "notes": [], + "params": { + "displayName": "200µl filtertiprack", + "loadName": "opentrons_96_tiprack_300ul", + "location": { + "slotName": "11" + }, + "namespace": "opentrons", + "version": 1 + }, + "result": { + "definition": { + "allowedRoles": [], + "brand": { + "brand": "Opentrons", + "brandId": [], + "links": [ + "https://shop.opentrons.com/collections/opentrons-tips/products/opentrons-300ul-tips" + ] + }, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + }, + "dimensions": { + "xDimension": 127.76, + "yDimension": 85.48, + "zDimension": 64.49 + }, + "gripperOffsets": {}, + "groups": [ + { + "metadata": {}, + "wells": [ + "A1", + "A10", + "A11", + "A12", + "A2", + "A3", + "A4", + "A5", + "A6", + "A7", + "A8", + "A9", + "B1", + "B10", + "B11", + "B12", + "B2", + "B3", + "B4", + "B5", + "B6", + "B7", + "B8", + "B9", + "C1", + "C10", + "C11", + "C12", + "C2", + "C3", + "C4", + "C5", + "C6", + "C7", + "C8", + "C9", + "D1", + "D10", + "D11", + "D12", + "D2", + "D3", + "D4", + "D5", + "D6", + "D7", + "D8", + "D9", + "E1", + "E10", + "E11", + "E12", + "E2", + "E3", + "E4", + "E5", + "E6", + "E7", + "E8", + "E9", + "F1", + "F10", + "F11", + "F12", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + "F8", + "F9", + "G1", + "G10", + "G11", + "G12", + "G2", + "G3", + "G4", + "G5", + "G6", + "G7", + "G8", + "G9", + "H1", + "H10", + "H11", + "H12", + "H2", + "H3", + "H4", + "H5", + "H6", + "H7", + "H8", + "H9" + ] + } + ], + "metadata": { + "displayCategory": "tipRack", + "displayName": "Opentrons OT-2 96 Tip Rack 300 µL", + "displayVolumeUnits": "µL", + "tags": [] + }, + "namespace": "opentrons", + "ordering": [ + [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1" + ], + [ + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10" + ], + [ + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11" + ], + [ + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ], + [ + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2" + ], + [ + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3" + ], + [ + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4" + ], + [ + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5" + ], + [ + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6" + ], + [ + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7" + ], + [ + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8" + ], + [ + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9" + ] + ], + "parameters": { + "format": "96Standard", + "isMagneticModuleCompatible": false, + "isTiprack": true, + "loadName": "opentrons_96_tiprack_300ul", + "tipLength": 59.3, + "tipOverlap": 7.47 + }, + "schemaVersion": 2, + "stackingOffsetWithLabware": {}, + "stackingOffsetWithModule": {}, + "version": 1, + "wells": { + "A1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 74.24, + "z": 5.39 + }, + "A10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 74.24, + "z": 5.39 + }, + "A11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 74.24, + "z": 5.39 + }, + "A12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 74.24, + "z": 5.39 + }, + "A2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 74.24, + "z": 5.39 + }, + "A3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 74.24, + "z": 5.39 + }, + "A4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 74.24, + "z": 5.39 + }, + "A5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 74.24, + "z": 5.39 + }, + "A6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 74.24, + "z": 5.39 + }, + "A7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 74.24, + "z": 5.39 + }, + "A8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 74.24, + "z": 5.39 + }, + "A9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 74.24, + "z": 5.39 + }, + "B1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 65.24, + "z": 5.39 + }, + "B10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 65.24, + "z": 5.39 + }, + "B11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 65.24, + "z": 5.39 + }, + "B12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 65.24, + "z": 5.39 + }, + "B2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 65.24, + "z": 5.39 + }, + "B3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 65.24, + "z": 5.39 + }, + "B4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 65.24, + "z": 5.39 + }, + "B5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 65.24, + "z": 5.39 + }, + "B6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 65.24, + "z": 5.39 + }, + "B7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 65.24, + "z": 5.39 + }, + "B8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 65.24, + "z": 5.39 + }, + "B9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 65.24, + "z": 5.39 + }, + "C1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 56.24, + "z": 5.39 + }, + "C10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 56.24, + "z": 5.39 + }, + "C11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 56.24, + "z": 5.39 + }, + "C12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 56.24, + "z": 5.39 + }, + "C2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 56.24, + "z": 5.39 + }, + "C3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 56.24, + "z": 5.39 + }, + "C4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 56.24, + "z": 5.39 + }, + "C5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 56.24, + "z": 5.39 + }, + "C6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 56.24, + "z": 5.39 + }, + "C7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 56.24, + "z": 5.39 + }, + "C8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 56.24, + "z": 5.39 + }, + "C9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 56.24, + "z": 5.39 + }, + "D1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 47.24, + "z": 5.39 + }, + "D10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 47.24, + "z": 5.39 + }, + "D11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 47.24, + "z": 5.39 + }, + "D12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 47.24, + "z": 5.39 + }, + "D2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 47.24, + "z": 5.39 + }, + "D3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 47.24, + "z": 5.39 + }, + "D4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 47.24, + "z": 5.39 + }, + "D5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 47.24, + "z": 5.39 + }, + "D6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 47.24, + "z": 5.39 + }, + "D7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 47.24, + "z": 5.39 + }, + "D8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 47.24, + "z": 5.39 + }, + "D9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 47.24, + "z": 5.39 + }, + "E1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 38.24, + "z": 5.39 + }, + "E10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 38.24, + "z": 5.39 + }, + "E11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 38.24, + "z": 5.39 + }, + "E12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 38.24, + "z": 5.39 + }, + "E2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 38.24, + "z": 5.39 + }, + "E3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 38.24, + "z": 5.39 + }, + "E4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 38.24, + "z": 5.39 + }, + "E5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 38.24, + "z": 5.39 + }, + "E6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 38.24, + "z": 5.39 + }, + "E7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 38.24, + "z": 5.39 + }, + "E8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 38.24, + "z": 5.39 + }, + "E9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 38.24, + "z": 5.39 + }, + "F1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 29.24, + "z": 5.39 + }, + "F10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 29.24, + "z": 5.39 + }, + "F11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 29.24, + "z": 5.39 + }, + "F12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 29.24, + "z": 5.39 + }, + "F2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 29.24, + "z": 5.39 + }, + "F3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 29.24, + "z": 5.39 + }, + "F4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 29.24, + "z": 5.39 + }, + "F5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 29.24, + "z": 5.39 + }, + "F6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 29.24, + "z": 5.39 + }, + "F7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 29.24, + "z": 5.39 + }, + "F8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 29.24, + "z": 5.39 + }, + "F9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 29.24, + "z": 5.39 + }, + "G1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 20.24, + "z": 5.39 + }, + "G10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 20.24, + "z": 5.39 + }, + "G11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 20.24, + "z": 5.39 + }, + "G12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 20.24, + "z": 5.39 + }, + "G2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 20.24, + "z": 5.39 + }, + "G3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 20.24, + "z": 5.39 + }, + "G4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 20.24, + "z": 5.39 + }, + "G5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 20.24, + "z": 5.39 + }, + "G6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 20.24, + "z": 5.39 + }, + "G7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 20.24, + "z": 5.39 + }, + "G8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 20.24, + "z": 5.39 + }, + "G9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 20.24, + "z": 5.39 + }, + "H1": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 14.38, + "y": 11.24, + "z": 5.39 + }, + "H10": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 95.38, + "y": 11.24, + "z": 5.39 + }, + "H11": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 104.38, + "y": 11.24, + "z": 5.39 + }, + "H12": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 113.38, + "y": 11.24, + "z": 5.39 + }, + "H2": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 23.38, + "y": 11.24, + "z": 5.39 + }, + "H3": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 32.38, + "y": 11.24, + "z": 5.39 + }, + "H4": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 41.38, + "y": 11.24, + "z": 5.39 + }, + "H5": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 50.38, + "y": 11.24, + "z": 5.39 + }, + "H6": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 59.38, + "y": 11.24, + "z": 5.39 + }, + "H7": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 68.38, + "y": 11.24, + "z": 5.39 + }, + "H8": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 77.38, + "y": 11.24, + "z": 5.39 + }, + "H9": { + "depth": 59.3, + "diameter": 5.23, + "shape": "circular", + "totalLiquidVolume": 300, + "x": 86.38, + "y": 11.24, + "z": 5.39 + } + } + } + }, + "status": "succeeded" + }, + { + "commandType": "loadLabware", + "notes": [], + "params": { + "displayName": "200µl filtertiprack", + "loadName": "opentrons_96_tiprack_20ul", + "location": { + "slotName": "4" + }, + "namespace": "opentrons", + "version": 1 + }, + "result": { + "definition": { + "allowedRoles": [], + "brand": { + "brand": "Opentrons", + "brandId": [], + "links": [ + "https://shop.opentrons.com/collections/opentrons-tips/products/opentrons-10ul-tips" + ] + }, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + }, + "dimensions": { + "xDimension": 127.76, + "yDimension": 85.48, + "zDimension": 64.69 + }, + "gripperOffsets": {}, + "groups": [ + { + "metadata": {}, + "wells": [ + "A1", + "A10", + "A11", + "A12", + "A2", + "A3", + "A4", + "A5", + "A6", + "A7", + "A8", + "A9", + "B1", + "B10", + "B11", + "B12", + "B2", + "B3", + "B4", + "B5", + "B6", + "B7", + "B8", + "B9", + "C1", + "C10", + "C11", + "C12", + "C2", + "C3", + "C4", + "C5", + "C6", + "C7", + "C8", + "C9", + "D1", + "D10", + "D11", + "D12", + "D2", + "D3", + "D4", + "D5", + "D6", + "D7", + "D8", + "D9", + "E1", + "E10", + "E11", + "E12", + "E2", + "E3", + "E4", + "E5", + "E6", + "E7", + "E8", + "E9", + "F1", + "F10", + "F11", + "F12", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + "F8", + "F9", + "G1", + "G10", + "G11", + "G12", + "G2", + "G3", + "G4", + "G5", + "G6", + "G7", + "G8", + "G9", + "H1", + "H10", + "H11", + "H12", + "H2", + "H3", + "H4", + "H5", + "H6", + "H7", + "H8", + "H9" + ] + } + ], + "metadata": { + "displayCategory": "tipRack", + "displayName": "Opentrons OT-2 96 Tip Rack 20 µL", + "displayVolumeUnits": "µL", + "tags": [] + }, + "namespace": "opentrons", + "ordering": [ + [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1" + ], + [ + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10" + ], + [ + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11" + ], + [ + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ], + [ + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2" + ], + [ + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3" + ], + [ + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4" + ], + [ + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5" + ], + [ + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6" + ], + [ + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7" + ], + [ + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8" + ], + [ + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9" + ] + ], + "parameters": { + "format": "96Standard", + "isMagneticModuleCompatible": false, + "isTiprack": true, + "loadName": "opentrons_96_tiprack_20ul", + "tipLength": 39.2, + "tipOverlap": 8.25 + }, + "schemaVersion": 2, + "stackingOffsetWithLabware": {}, + "stackingOffsetWithModule": {}, + "version": 1, + "wells": { + "A1": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 14.38, + "y": 74.24, + "z": 25.49 + }, + "A10": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 95.38, + "y": 74.24, + "z": 25.49 + }, + "A11": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 104.38, + "y": 74.24, + "z": 25.49 + }, + "A12": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 113.38, + "y": 74.24, + "z": 25.49 + }, + "A2": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 23.38, + "y": 74.24, + "z": 25.49 + }, + "A3": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 32.38, + "y": 74.24, + "z": 25.49 + }, + "A4": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 41.38, + "y": 74.24, + "z": 25.49 + }, + "A5": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 50.38, + "y": 74.24, + "z": 25.49 + }, + "A6": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 59.38, + "y": 74.24, + "z": 25.49 + }, + "A7": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 68.38, + "y": 74.24, + "z": 25.49 + }, + "A8": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 77.38, + "y": 74.24, + "z": 25.49 + }, + "A9": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 86.38, + "y": 74.24, + "z": 25.49 + }, + "B1": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 14.38, + "y": 65.24, + "z": 25.49 + }, + "B10": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 95.38, + "y": 65.24, + "z": 25.49 + }, + "B11": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 104.38, + "y": 65.24, + "z": 25.49 + }, + "B12": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 113.38, + "y": 65.24, + "z": 25.49 + }, + "B2": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 23.38, + "y": 65.24, + "z": 25.49 + }, + "B3": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 32.38, + "y": 65.24, + "z": 25.49 + }, + "B4": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 41.38, + "y": 65.24, + "z": 25.49 + }, + "B5": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 50.38, + "y": 65.24, + "z": 25.49 + }, + "B6": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 59.38, + "y": 65.24, + "z": 25.49 + }, + "B7": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 68.38, + "y": 65.24, + "z": 25.49 + }, + "B8": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 77.38, + "y": 65.24, + "z": 25.49 + }, + "B9": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 86.38, + "y": 65.24, + "z": 25.49 + }, + "C1": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 14.38, + "y": 56.24, + "z": 25.49 + }, + "C10": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 95.38, + "y": 56.24, + "z": 25.49 + }, + "C11": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 104.38, + "y": 56.24, + "z": 25.49 + }, + "C12": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 113.38, + "y": 56.24, + "z": 25.49 + }, + "C2": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 23.38, + "y": 56.24, + "z": 25.49 + }, + "C3": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 32.38, + "y": 56.24, + "z": 25.49 + }, + "C4": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 41.38, + "y": 56.24, + "z": 25.49 + }, + "C5": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 50.38, + "y": 56.24, + "z": 25.49 + }, + "C6": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 59.38, + "y": 56.24, + "z": 25.49 + }, + "C7": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 68.38, + "y": 56.24, + "z": 25.49 + }, + "C8": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 77.38, + "y": 56.24, + "z": 25.49 + }, + "C9": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 86.38, + "y": 56.24, + "z": 25.49 + }, + "D1": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 14.38, + "y": 47.24, + "z": 25.49 + }, + "D10": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 95.38, + "y": 47.24, + "z": 25.49 + }, + "D11": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 104.38, + "y": 47.24, + "z": 25.49 + }, + "D12": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 113.38, + "y": 47.24, + "z": 25.49 + }, + "D2": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 23.38, + "y": 47.24, + "z": 25.49 + }, + "D3": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 32.38, + "y": 47.24, + "z": 25.49 + }, + "D4": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 41.38, + "y": 47.24, + "z": 25.49 + }, + "D5": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 50.38, + "y": 47.24, + "z": 25.49 + }, + "D6": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 59.38, + "y": 47.24, + "z": 25.49 + }, + "D7": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 68.38, + "y": 47.24, + "z": 25.49 + }, + "D8": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 77.38, + "y": 47.24, + "z": 25.49 + }, + "D9": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 86.38, + "y": 47.24, + "z": 25.49 + }, + "E1": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 14.38, + "y": 38.24, + "z": 25.49 + }, + "E10": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 95.38, + "y": 38.24, + "z": 25.49 + }, + "E11": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 104.38, + "y": 38.24, + "z": 25.49 + }, + "E12": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 113.38, + "y": 38.24, + "z": 25.49 + }, + "E2": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 23.38, + "y": 38.24, + "z": 25.49 + }, + "E3": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 32.38, + "y": 38.24, + "z": 25.49 + }, + "E4": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 41.38, + "y": 38.24, + "z": 25.49 + }, + "E5": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 50.38, + "y": 38.24, + "z": 25.49 + }, + "E6": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 59.38, + "y": 38.24, + "z": 25.49 + }, + "E7": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 68.38, + "y": 38.24, + "z": 25.49 + }, + "E8": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 77.38, + "y": 38.24, + "z": 25.49 + }, + "E9": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 86.38, + "y": 38.24, + "z": 25.49 + }, + "F1": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 14.38, + "y": 29.24, + "z": 25.49 + }, + "F10": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 95.38, + "y": 29.24, + "z": 25.49 + }, + "F11": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 104.38, + "y": 29.24, + "z": 25.49 + }, + "F12": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 113.38, + "y": 29.24, + "z": 25.49 + }, + "F2": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 23.38, + "y": 29.24, + "z": 25.49 + }, + "F3": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 32.38, + "y": 29.24, + "z": 25.49 + }, + "F4": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 41.38, + "y": 29.24, + "z": 25.49 + }, + "F5": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 50.38, + "y": 29.24, + "z": 25.49 + }, + "F6": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 59.38, + "y": 29.24, + "z": 25.49 + }, + "F7": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 68.38, + "y": 29.24, + "z": 25.49 + }, + "F8": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 77.38, + "y": 29.24, + "z": 25.49 + }, + "F9": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 86.38, + "y": 29.24, + "z": 25.49 + }, + "G1": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 14.38, + "y": 20.24, + "z": 25.49 + }, + "G10": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 95.38, + "y": 20.24, + "z": 25.49 + }, + "G11": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 104.38, + "y": 20.24, + "z": 25.49 + }, + "G12": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 113.38, + "y": 20.24, + "z": 25.49 + }, + "G2": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 23.38, + "y": 20.24, + "z": 25.49 + }, + "G3": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 32.38, + "y": 20.24, + "z": 25.49 + }, + "G4": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 41.38, + "y": 20.24, + "z": 25.49 + }, + "G5": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 50.38, + "y": 20.24, + "z": 25.49 + }, + "G6": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 59.38, + "y": 20.24, + "z": 25.49 + }, + "G7": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 68.38, + "y": 20.24, + "z": 25.49 + }, + "G8": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 77.38, + "y": 20.24, + "z": 25.49 + }, + "G9": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 86.38, + "y": 20.24, + "z": 25.49 + }, + "H1": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 14.38, + "y": 11.24, + "z": 25.49 + }, + "H10": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 95.38, + "y": 11.24, + "z": 25.49 + }, + "H11": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 104.38, + "y": 11.24, + "z": 25.49 + }, + "H12": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 113.38, + "y": 11.24, + "z": 25.49 + }, + "H2": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 23.38, + "y": 11.24, + "z": 25.49 + }, + "H3": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 32.38, + "y": 11.24, + "z": 25.49 + }, + "H4": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 41.38, + "y": 11.24, + "z": 25.49 + }, + "H5": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 50.38, + "y": 11.24, + "z": 25.49 + }, + "H6": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 59.38, + "y": 11.24, + "z": 25.49 + }, + "H7": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 68.38, + "y": 11.24, + "z": 25.49 + }, + "H8": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 77.38, + "y": 11.24, + "z": 25.49 + }, + "H9": { + "depth": 39.2, + "diameter": 3.27, + "shape": "circular", + "totalLiquidVolume": 20, + "x": 86.38, + "y": 11.24, + "z": 25.49 + } + } + } + }, + "status": "succeeded" + }, + { + "commandType": "loadPipette", + "notes": [], + "params": { + "mount": "left", + "pipetteName": "p300_multi_gen2" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Setting Temperature Module temperature to 4.0 °C (rounded off to nearest integer)", + "legacyCommandType": "command.TEMPDECK_SET_TEMP" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "pickUpTip", + "notes": [], + "params": { + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "tipDiameter": 0, + "tipLength": 31.000000000000004, + "tipVolume": 20 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 3.333333333333343, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 3.333333333333343 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 13.333333333333343, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 13.333333333333343 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 3.333333333333343, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 3.333333333333343 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 13.333333333333343, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 13.333333333333343 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 3.333333333333343, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 3.333333333333343 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 13.333333333333343, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 13.333333333333343 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 50.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dropTip", + "notes": [], + "params": { + "alternateDropLocation": false, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "default" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "waitForResume", + "notes": [], + "params": { + "message": "mix for 10 minutes off-deck in a heatershaker" + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Engaging Magnetic Module", + "legacyCommandType": "command.MAGDECK_ENGAGE" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Delaying for 7 minutes and 0.0 seconds. Incubating on MagDeck for 7 minutes.", + "legacyCommandType": "command.DELAY" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "pickUpTip", + "notes": [], + "params": { + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "tipDiameter": 0, + "tipLength": 31.000000000000004, + "tipVolume": 20 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 6.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 16.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.0 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 6.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 16.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.0 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 6.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 16.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.0 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 6.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 16.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.0 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 6.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 16.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.0 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dropTip", + "notes": [], + "params": { + "alternateDropLocation": false, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "default" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Disengaging Magnetic Module", + "legacyCommandType": "command.MAGDECK_DISENGAGE" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "pickUpTip", + "notes": [], + "params": { + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A3" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "tipDiameter": 0, + "tipLength": 31.000000000000004, + "tipVolume": 20 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 6.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 16.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 6.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 16.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 6.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 16.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dropTip", + "notes": [], + "params": { + "alternateDropLocation": false, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "default" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Engaging Magnetic Module", + "legacyCommandType": "command.MAGDECK_ENGAGE" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Delaying for 7 minutes and 0.0 seconds. Incubating on MagDeck for 7 minutes.", + "legacyCommandType": "command.DELAY" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "pickUpTip", + "notes": [], + "params": { + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A4" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "tipDiameter": 0, + "tipLength": 31.000000000000004, + "tipVolume": 20 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 6.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 16.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 6.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 16.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 6.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 16.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dropTip", + "notes": [], + "params": { + "alternateDropLocation": false, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "default" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Disengaging Magnetic Module", + "legacyCommandType": "command.MAGDECK_DISENGAGE" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "pickUpTip", + "notes": [], + "params": { + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A5" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "tipDiameter": 0, + "tipLength": 31.000000000000004, + "tipVolume": 20 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 6.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 16.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 6.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 16.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 6.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 16.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dropTip", + "notes": [], + "params": { + "alternateDropLocation": false, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "default" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Engaging Magnetic Module", + "legacyCommandType": "command.MAGDECK_ENGAGE" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Delaying for 7 minutes and 0.0 seconds. Incubating on MagDeck for 7 minutes.", + "legacyCommandType": "command.DELAY" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "pickUpTip", + "notes": [], + "params": { + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "tipDiameter": 0, + "tipLength": 31.000000000000004, + "tipVolume": 20 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 6.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 16.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 6.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 16.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 6.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 16.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dropTip", + "notes": [], + "params": { + "alternateDropLocation": false, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "default" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Disengaging Magnetic Module", + "legacyCommandType": "command.MAGDECK_DISENGAGE" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "pickUpTip", + "notes": [], + "params": { + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A7" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "tipDiameter": 0, + "tipLength": 31.000000000000004, + "tipVolume": 20 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 6.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 16.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 6.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 16.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 6.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 16.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dropTip", + "notes": [], + "params": { + "alternateDropLocation": false, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "default" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Engaging Magnetic Module", + "legacyCommandType": "command.MAGDECK_ENGAGE" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Delaying for 7 minutes and 0.0 seconds. Incubating on MagDeck for 7 minutes.", + "legacyCommandType": "command.DELAY" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "pickUpTip", + "notes": [], + "params": { + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A8" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "tipDiameter": 0, + "tipLength": 31.000000000000004, + "tipVolume": 20 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 6.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 16.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 6.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 16.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 6.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 16.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dropTip", + "notes": [], + "params": { + "alternateDropLocation": false, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "default" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Disengaging Magnetic Module", + "legacyCommandType": "command.MAGDECK_DISENGAGE" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "pickUpTip", + "notes": [], + "params": { + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A9" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "tipDiameter": 0, + "tipLength": 31.000000000000004, + "tipVolume": 20 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dropTip", + "notes": [], + "params": { + "alternateDropLocation": false, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "default" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Engaging Magnetic Module", + "legacyCommandType": "command.MAGDECK_ENGAGE" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Delaying for 7 minutes and 0.0 seconds. Incubating on MagDeck for 7 minutes.", + "legacyCommandType": "command.DELAY" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "pickUpTip", + "notes": [], + "params": { + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A10" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "tipDiameter": 0, + "tipLength": 31.000000000000004, + "tipVolume": 20 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dropTip", + "notes": [], + "params": { + "alternateDropLocation": false, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "default" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Disengaging Magnetic Module", + "legacyCommandType": "command.MAGDECK_DISENGAGE" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "pickUpTip", + "notes": [], + "params": { + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A11" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "tipDiameter": 0, + "tipLength": 31.000000000000004, + "tipVolume": 20 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dropTip", + "notes": [], + "params": { + "alternateDropLocation": false, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "default" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "waitForResume", + "notes": [], + "params": { + "message": "Incubating for 10 minutes for DNase 1 treatment with occasional mixing." + }, + "status": "succeeded" + }, + { + "commandType": "pickUpTip", + "notes": [], + "params": { + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A12" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "tipDiameter": 0, + "tipLength": 31.000000000000004, + "tipVolume": 20 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 6.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 16.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 6.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 16.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 20.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 20.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 6.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 6.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 16.666666666666657, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 16.666666666666657 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 18.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 18.0 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dropTip", + "notes": [], + "params": { + "alternateDropLocation": false, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "default" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "waitForResume", + "notes": [], + "params": { + "message": "Incubating for 10 minutes with occasional mixing for stop reaction" + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Engaging Magnetic Module", + "legacyCommandType": "command.MAGDECK_ENGAGE" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Delaying for 7 minutes and 0.0 seconds. Incubating on MagDeck for 7 minutes.", + "legacyCommandType": "command.DELAY" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "pickUpTip", + "notes": [], + "params": { + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "tipDiameter": 0, + "tipLength": 51.099999999999994, + "tipVolume": 300 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 166.66666666666666, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 166.66666666666666 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 176.66666666666666, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 176.66666666666666 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 166.66666666666666, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 166.66666666666666 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 176.66666666666666, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 176.66666666666666 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 166.66666666666666, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 166.66666666666666 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 176.66666666666666, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 176.66666666666666 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 30.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dropTip", + "notes": [], + "params": { + "alternateDropLocation": false, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "default" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Delaying for 10 minutes and 0.0 seconds. dry beads for 10 minute", + "legacyCommandType": "command.DELAY" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "pickUpTip", + "notes": [], + "params": { + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "tipDiameter": 0, + "tipLength": 51.099999999999994, + "tipVolume": 300 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 50.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A12" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 50.0 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 50.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 50.0 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to A1 of deepwell plate on Magnetic Module GEN2 on 6", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dropTip", + "notes": [], + "params": { + "alternateDropLocation": false, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "default" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Engaging Magnetic Module", + "legacyCommandType": "command.MAGDECK_ENGAGE" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Delaying for 7 minutes and 0.0 seconds. Incubating on MagDeck for 7 minutes.", + "legacyCommandType": "command.DELAY" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "pickUpTip", + "notes": [], + "params": { + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A3" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "tipDiameter": 0, + "tipLength": 51.099999999999994, + "tipVolume": 300 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 50.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 50.0 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 500.0, + "volume": 60.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 60.0 + }, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 300.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 150.0, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dropTip", + "notes": [], + "params": { + "alternateDropLocation": false, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "default" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + } + ], + "config": { + "apiVersion": [ + 2, + 4 + ], + "protocolType": "python" + }, + "errors": [], + "files": [ + { + "name": "OT2_S_v2_4_P300M_None_MM_TM_Zymo.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [ + { + "definitionUri": "opentrons/opentrons_1_trash_1100ml_fixed/1", + "loadName": "opentrons_1_trash_1100ml_fixed", + "location": { + "slotName": "12" + } + }, + { + "definitionUri": "opentrons/nest_96_wellplate_2ml_deep/1", + "displayName": "deepwell plate", + "loadName": "nest_96_wellplate_2ml_deep", + "location": {} + }, + { + "definitionUri": "opentrons/opentrons_96_aluminumblock_nest_wellplate_100ul/1", + "loadName": "opentrons_96_aluminumblock_nest_wellplate_100ul", + "location": {} + }, + { + "definitionUri": "opentrons/nest_1_reservoir_195ml/1", + "displayName": "Liquid Waste", + "loadName": "nest_1_reservoir_195ml", + "location": { + "slotName": "9" + } + }, + { + "definitionUri": "opentrons/nest_12_reservoir_15ml/1", + "displayName": "reagent reservoir 2", + "loadName": "nest_12_reservoir_15ml", + "location": { + "slotName": "3" + } + }, + { + "definitionUri": "opentrons/nest_12_reservoir_15ml/1", + "displayName": "reagent reservoir 1", + "loadName": "nest_12_reservoir_15ml", + "location": { + "slotName": "2" + } + }, + { + "definitionUri": "opentrons/opentrons_96_tiprack_300ul/1", + "displayName": "200µl filtertiprack", + "loadName": "opentrons_96_tiprack_300ul", + "location": { + "slotName": "5" + } + }, + { + "definitionUri": "opentrons/opentrons_96_tiprack_300ul/1", + "displayName": "200µl filtertiprack", + "loadName": "opentrons_96_tiprack_300ul", + "location": { + "slotName": "7" + } + }, + { + "definitionUri": "opentrons/opentrons_96_tiprack_300ul/1", + "displayName": "200µl filtertiprack", + "loadName": "opentrons_96_tiprack_300ul", + "location": { + "slotName": "8" + } + }, + { + "definitionUri": "opentrons/opentrons_96_tiprack_300ul/1", + "displayName": "200µl filtertiprack", + "loadName": "opentrons_96_tiprack_300ul", + "location": { + "slotName": "10" + } + }, + { + "definitionUri": "opentrons/opentrons_96_tiprack_300ul/1", + "displayName": "200µl filtertiprack", + "loadName": "opentrons_96_tiprack_300ul", + "location": { + "slotName": "11" + } + }, + { + "definitionUri": "opentrons/opentrons_96_tiprack_20ul/1", + "displayName": "200µl filtertiprack", + "loadName": "opentrons_96_tiprack_20ul", + "location": { + "slotName": "4" + } + } + ], + "liquids": [], + "metadata": { + "apiLevel": "2.4", + "author": "Opentrons ", + "protocolName": "Zymo Direct-zol96 Magbead RNA" + }, + "modules": [ + { + "location": { + "slotName": "6" + }, + "model": "magneticModuleV2" + }, + { + "location": { + "slotName": "1" + }, + "model": "temperatureModuleV2" + } + ], + "pipettes": [ + { + "mount": "left", + "pipetteName": "p300_multi_gen2" + } + ], + "robotType": "OT-2 Standard", + "runTimeParameters": [] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1e5825a070][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_minimum].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1e5825a070][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_minimum].json new file mode 100644 index 00000000000..20c34cf527c --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[1e5825a070][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_minimum].json @@ -0,0 +1,74 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + } + ], + "config": { + "apiVersion": [ + 2, + 18 + ], + "protocolType": "python" + }, + "errors": [ + { + "detail": "ParameterDefinitionError [line 95]: Minimum is type 'str', but must be of parameter type 'int'", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ExceptionInProtocolError", + "wrappedErrors": [ + { + "detail": "opentrons.protocols.parameters.types.ParameterDefinitionError: Minimum is type 'str', but must be of parameter type 'int'", + "errorCode": "4000", + "errorInfo": { + "args": "(\"Minimum is type 'str', but must be of parameter type 'int'\",)", + "class": "ParameterDefinitionError", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 80, in _parse_and_set_parameters\n exec(\"add_parameters(__param_context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_minimum.py\", line 95, in add_parameters\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/_parameter_context.py\", line 56, in add_int\n parameter = parameter_definition.create_int_parameter(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 178, in create_int_parameter\n return ParameterDefinition(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 73, in __init__\n validation.validate_options(default, minimum, maximum, choices, parameter_type)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/validation.py\", line 266, in validate_options\n _validate_min_and_max(minimum, maximum, parameter_type)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/validation.py\", line 213, in _validate_min_and_max\n raise ParameterDefinitionError(\n" + }, + "errorType": "PythonException", + "wrappedErrors": [] + } + ] + } + ], + "files": [ + { + "name": "Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_minimum.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "protocolName": "Description Too Long 2.18" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-3 Standard", + "runTimeParameters": [] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[24a6b167a7][OT2_X_v2_18_None_None_NoRTPdisplay_name].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[24a6b167a7][OT2_X_v2_18_None_None_NoRTPdisplay_name].json new file mode 100644 index 00000000000..1d6692d3961 --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[24a6b167a7][OT2_X_v2_18_None_None_NoRTPdisplay_name].json @@ -0,0 +1,74 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + } + ], + "config": { + "apiVersion": [ + 2, + 18 + ], + "protocolType": "python" + }, + "errors": [ + { + "detail": "TypeError [line 11]: ParameterContext.add_int() missing 1 required positional argument: 'display_name'", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ExceptionInProtocolError", + "wrappedErrors": [ + { + "detail": "TypeError: ParameterContext.add_int() missing 1 required positional argument: 'display_name'", + "errorCode": "4000", + "errorInfo": { + "args": "(\"ParameterContext.add_int() missing 1 required positional argument: 'display_name'\",)", + "class": "TypeError", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 80, in _parse_and_set_parameters\n exec(\"add_parameters(__param_context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"OT2_X_v2_18_None_None_NoRTPdisplay_name.py\", line 11, in add_parameters\n" + }, + "errorType": "PythonException", + "wrappedErrors": [] + } + ] + } + ], + "files": [ + { + "name": "OT2_X_v2_18_None_None_NoRTPdisplay_name.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "protocolName": "No RTP Display Name" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-2 Standard", + "runTimeParameters": [] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[25f79fd65e][Flex_None_None_TM_2_16_AnalysisError_ModuleInStagingAreaCol3].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[25f79fd65e][Flex_None_None_TM_2_16_AnalysisError_ModuleInStagingAreaCol3].json deleted file mode 100644 index 74cf05cce32..00000000000 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[25f79fd65e][Flex_None_None_TM_2_16_AnalysisError_ModuleInStagingAreaCol3].json +++ /dev/null @@ -1,629 +0,0 @@ -{ - "commands": [ - { - "commandType": "home", - "notes": [], - "params": {}, - "result": {}, - "status": "succeeded" - }, - { - "commandType": "loadLabware", - "notes": [], - "params": { - "loadName": "nest_1_reservoir_290ml", - "location": { - "addressableAreaName": "C4" - }, - "namespace": "opentrons", - "version": 1 - }, - "result": { - "definition": { - "allowedRoles": [], - "brand": { - "brand": "NEST", - "brandId": [ - "360206", - "360266" - ], - "links": [ - "https://www.nest-biotech.com/reagent-reserviors" - ] - }, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - }, - "dimensions": { - "xDimension": 127.76, - "yDimension": 85.47, - "zDimension": 44.4 - }, - "gripperOffsets": {}, - "groups": [ - { - "metadata": { - "wellBottomShape": "v" - }, - "wells": [ - "A1" - ] - } - ], - "metadata": { - "displayCategory": "reservoir", - "displayName": "NEST 1 Well Reservoir 290 mL", - "displayVolumeUnits": "mL", - "tags": [] - }, - "namespace": "opentrons", - "ordering": [ - [ - "A1" - ] - ], - "parameters": { - "format": "trough", - "isMagneticModuleCompatible": false, - "isTiprack": false, - "loadName": "nest_1_reservoir_290ml", - "quirks": [ - "centerMultichannelOnWells", - "touchTipDisabled" - ] - }, - "schemaVersion": 2, - "stackingOffsetWithLabware": {}, - "stackingOffsetWithModule": {}, - "version": 1, - "wells": { - "A1": { - "depth": 39.55, - "shape": "rectangular", - "totalLiquidVolume": 290000, - "x": 63.88, - "xDimension": 106.8, - "y": 42.74, - "yDimension": 71.2, - "z": 4.85 - } - } - } - }, - "status": "succeeded" - }, - { - "commandType": "loadModule", - "notes": [], - "params": { - "location": { - "slotName": "C3" - }, - "model": "temperatureModuleV2" - }, - "result": { - "definition": { - "calibrationPoint": { - "x": 11.7, - "y": 8.75, - "z": 80.09 - }, - "compatibleWith": [ - "temperatureModuleV1" - ], - "dimensions": { - "bareOverallHeight": 84.0, - "overLabwareHeight": 0.0 - }, - "displayName": "Temperature Module GEN2", - "gripperOffsets": { - "default": { - "dropOffset": { - "x": 0.0, - "y": 0.0, - "z": 1.0 - }, - "pickUpOffset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - } - } - }, - "labwareOffset": { - "x": -1.45, - "y": -0.15, - "z": 80.09 - }, - "model": "temperatureModuleV2", - "moduleType": "temperatureModuleType", - "otSharedSchema": "module/schemas/2", - "quirks": [], - "slotTransforms": { - "ot2_short_trash": { - "3": { - "labwareOffset": [ - [ - -1, - -0.15, - 0, - 0 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - }, - "6": { - "labwareOffset": [ - [ - -1, - -0.15, - 0, - 0 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - }, - "9": { - "labwareOffset": [ - [ - -1, - -0.15, - 0, - 0 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - } - }, - "ot2_standard": { - "3": { - "labwareOffset": [ - [ - -1, - -0.3, - 0, - 0 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - }, - "6": { - "labwareOffset": [ - [ - -1, - -0.3, - 0, - 0 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - }, - "9": { - "labwareOffset": [ - [ - -1, - -0.3, - 0, - 0 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - } - }, - "ot3_standard": { - "A1": { - "labwareOffset": [ - [ - -71.09, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.15, - 1 - ], - [ - 0, - 0, - 1, - 1.45 - ] - ] - }, - "A3": { - "labwareOffset": [ - [ - -71.09, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.15, - 1 - ], - [ - 0, - 0, - 1, - 1.45 - ] - ] - }, - "B1": { - "labwareOffset": [ - [ - -71.09, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.15, - 1 - ], - [ - 0, - 0, - 1, - 1.45 - ] - ] - }, - "B3": { - "labwareOffset": [ - [ - -71.09, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.15, - 1 - ], - [ - 0, - 0, - 1, - 1.45 - ] - ] - }, - "C1": { - "labwareOffset": [ - [ - -71.09, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.15, - 1 - ], - [ - 0, - 0, - 1, - 1.45 - ] - ] - }, - "C3": { - "labwareOffset": [ - [ - -71.09, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.15, - 1 - ], - [ - 0, - 0, - 1, - 1.45 - ] - ] - }, - "D1": { - "labwareOffset": [ - [ - -71.09, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.15, - 1 - ], - [ - 0, - 0, - 1, - 1.45 - ] - ] - }, - "D3": { - "labwareOffset": [ - [ - -71.09, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.15, - 1 - ], - [ - 0, - 0, - 1, - 1.45 - ] - ] - } - } - } - }, - "model": "temperatureModuleV2" - }, - "status": "succeeded" - } - ], - "config": { - "apiVersion": [ - 2, - 16 - ], - "protocolType": "python" - }, - "errors": [ - { - "detail": "DeckConflictError [line 17]: nest_1_reservoir_290ml in slot C4 prevents temperatureModuleV2 from using slot C3.", - "errorCode": "4000", - "errorInfo": {}, - "errorType": "ExceptionInProtocolError", - "wrappedErrors": [ - { - "detail": "opentrons.motion_planning.deck_conflict.DeckConflictError: nest_1_reservoir_290ml in slot C4 prevents temperatureModuleV2 from using slot C3.", - "errorCode": "4000", - "errorInfo": { - "args": "('nest_1_reservoir_290ml in slot C4 prevents temperatureModuleV2 from using slot C3.',)", - "class": "DeckConflictError", - "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_None_None_TM_2_16_AnalysisError_ModuleInStagingAreaCol3.py\", line 17, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line 383, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/protocol_context.py\", line 814, in load_module\n module_core = self._core.load_module(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/engine/protocol.py\", line 424, in load_module\n deck_conflict.check(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/engine/deck_conflict.py\", line 203, in check\n wrapped_deck_conflict.check(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/motion_planning/deck_conflict.py\", line 223, in check\n raise DeckConflictError(\n" - }, - "errorType": "PythonException", - "wrappedErrors": [] - } - ] - } - ], - "files": [ - { - "name": "Flex_None_None_TM_2_16_AnalysisError_ModuleInStagingAreaCol3.py", - "role": "main" - }, - { - "name": "cpx_4_tuberack_100ul.json", - "role": "labware" - }, - { - "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", - "role": "labware" - }, - { - "name": "opentrons_ot3_96_tiprack_200ul_rss.json", - "role": "labware" - }, - { - "name": "opentrons_ot3_96_tiprack_50ul_rss.json", - "role": "labware" - }, - { - "name": "sample_labware.json", - "role": "labware" - } - ], - "labware": [ - { - "definitionUri": "opentrons/nest_1_reservoir_290ml/1", - "loadName": "nest_1_reservoir_290ml", - "location": { - "addressableAreaName": "C4" - } - } - ], - "liquids": [], - "metadata": { - "author": "Derek Maggio ", - "protocolName": "QA Protocol - Analysis Error - Module in Staging Area Column 3" - }, - "modules": [ - { - "location": { - "slotName": "C3" - }, - "model": "temperatureModuleV2" - } - ], - "pipettes": [], - "robotType": "OT-3 Standard", - "runTimeParameters": [] -} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[e99c0a71d5][Flex_P1000_96_Gripper_2_16_TriggerPrepareForMountMovement].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[2eaf98de6a][Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_TriggerPrepareForMountMovement].json similarity index 97% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[e99c0a71d5][Flex_P1000_96_Gripper_2_16_TriggerPrepareForMountMovement].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[2eaf98de6a][Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_TriggerPrepareForMountMovement].json index bd42f6ff8a7..cd97f5c0023 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[e99c0a71d5][Flex_P1000_96_Gripper_2_16_TriggerPrepareForMountMovement].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[2eaf98de6a][Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_TriggerPrepareForMountMovement].json @@ -2,12 +2,14 @@ "commands": [ { "commandType": "home", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "loadModule", + "notes": [], "params": { "location": { "slotName": "B1" @@ -116,6 +118,7 @@ }, { "commandType": "loadModule", + "notes": [], "params": { "location": { "slotName": "A3" @@ -170,6 +173,7 @@ }, { "commandType": "loadModule", + "notes": [], "params": { "location": { "slotName": "D1" @@ -619,6 +623,7 @@ }, { "commandType": "loadModule", + "notes": [], "params": { "location": { "slotName": "C1" @@ -1070,12 +1075,14 @@ }, { "commandType": "thermocycler/openLid", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "heaterShaker/openLabwareLatch", + "notes": [], "params": {}, "result": { "pipetteRetracted": true @@ -1084,6 +1091,7 @@ }, { "commandType": "loadLabware", + "notes": [], "params": { "loadName": "opentrons_96_well_aluminum_block", "location": {}, @@ -2240,6 +2248,7 @@ }, { "commandType": "loadLabware", + "notes": [], "params": { "loadName": "opentrons_96_pcr_adapter", "location": {}, @@ -3396,6 +3405,7 @@ }, { "commandType": "loadLabware", + "notes": [], "params": { "loadName": "nest_96_wellplate_2ml_deep", "location": { @@ -4662,6 +4672,7 @@ }, { "commandType": "loadLabware", + "notes": [], "params": { "loadName": "nest_96_wellplate_100ul_pcr_full_skirt", "location": { @@ -5829,6 +5840,7 @@ }, { "commandType": "loadLabware", + "notes": [], "params": { "loadName": "opentrons_flex_96_tiprack_adapter", "location": { @@ -5891,6 +5903,7 @@ }, { "commandType": "loadLabware", + "notes": [], "params": { "loadName": "opentrons_flex_96_tiprack_1000ul", "location": {}, @@ -7040,6 +7053,7 @@ }, { "commandType": "loadLabware", + "notes": [], "params": { "loadName": "opentrons_flex_96_tiprack_1000ul", "location": { @@ -8191,6 +8205,7 @@ }, { "commandType": "loadLabware", + "notes": [], "params": { "loadName": "opentrons_flex_96_tiprack_1000ul", "location": { @@ -9342,6 +9357,7 @@ }, { "commandType": "loadPipette", + "notes": [], "params": { "mount": "left", "pipetteName": "p1000_96" @@ -9351,6 +9367,7 @@ }, { "commandType": "loadLiquid", + "notes": [], "params": { "volumeByWell": { "A1": 29000.0 @@ -9361,6 +9378,7 @@ }, { "commandType": "configureNozzleLayout", + "notes": [], "params": { "configurationParams": { "primaryNozzle": "A12", @@ -9372,6 +9390,7 @@ }, { "commandType": "pickUpTip", + "notes": [], "params": { "wellLocation": { "offset": { @@ -9397,6 +9416,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -9422,6 +9442,7 @@ }, { "commandType": "touchTip", + "notes": [], "params": { "radius": 1.0, "speed": 60.0, @@ -9446,6 +9467,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -9471,6 +9493,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", + "notes": [], "params": { "addressableAreaName": "movableTrashB3", "alternateDropLocation": true, @@ -9493,12 +9516,14 @@ }, { "commandType": "dropTipInPlace", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "pickUpTip", + "notes": [], "params": { "wellLocation": { "offset": { @@ -9524,6 +9549,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -9549,6 +9575,7 @@ }, { "commandType": "touchTip", + "notes": [], "params": { "radius": 1.0, "speed": 60.0, @@ -9573,6 +9600,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -9598,6 +9626,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", + "notes": [], "params": { "addressableAreaName": "movableTrashB3", "alternateDropLocation": true, @@ -9620,12 +9649,14 @@ }, { "commandType": "dropTipInPlace", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "pickUpTip", + "notes": [], "params": { "wellLocation": { "offset": { @@ -9651,6 +9682,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -9676,6 +9708,7 @@ }, { "commandType": "touchTip", + "notes": [], "params": { "radius": 1.0, "speed": 60.0, @@ -9700,6 +9733,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -9725,6 +9759,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", + "notes": [], "params": { "addressableAreaName": "movableTrashB3", "alternateDropLocation": true, @@ -9747,12 +9782,14 @@ }, { "commandType": "dropTipInPlace", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "pickUpTip", + "notes": [], "params": { "wellLocation": { "offset": { @@ -9778,6 +9815,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -9803,6 +9841,7 @@ }, { "commandType": "touchTip", + "notes": [], "params": { "radius": 1.0, "speed": 60.0, @@ -9827,6 +9866,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -9852,6 +9892,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", + "notes": [], "params": { "addressableAreaName": "movableTrashB3", "alternateDropLocation": true, @@ -9874,12 +9915,14 @@ }, { "commandType": "dropTipInPlace", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "pickUpTip", + "notes": [], "params": { "wellLocation": { "offset": { @@ -9905,6 +9948,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -9930,6 +9974,7 @@ }, { "commandType": "touchTip", + "notes": [], "params": { "radius": 1.0, "speed": 60.0, @@ -9954,6 +9999,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -9979,6 +10025,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", + "notes": [], "params": { "addressableAreaName": "movableTrashB3", "alternateDropLocation": true, @@ -10001,12 +10048,14 @@ }, { "commandType": "dropTipInPlace", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "pickUpTip", + "notes": [], "params": { "wellLocation": { "offset": { @@ -10032,6 +10081,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -10057,6 +10107,7 @@ }, { "commandType": "touchTip", + "notes": [], "params": { "radius": 1.0, "speed": 60.0, @@ -10081,6 +10132,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -10106,6 +10158,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", + "notes": [], "params": { "addressableAreaName": "movableTrashB3", "alternateDropLocation": true, @@ -10128,12 +10181,14 @@ }, { "commandType": "dropTipInPlace", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "pickUpTip", + "notes": [], "params": { "wellLocation": { "offset": { @@ -10159,6 +10214,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -10184,6 +10240,7 @@ }, { "commandType": "touchTip", + "notes": [], "params": { "radius": 1.0, "speed": 60.0, @@ -10208,6 +10265,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -10233,6 +10291,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", + "notes": [], "params": { "addressableAreaName": "movableTrashB3", "alternateDropLocation": true, @@ -10255,12 +10314,14 @@ }, { "commandType": "dropTipInPlace", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "pickUpTip", + "notes": [], "params": { "wellLocation": { "offset": { @@ -10286,6 +10347,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -10311,6 +10373,7 @@ }, { "commandType": "touchTip", + "notes": [], "params": { "radius": 1.0, "speed": 60.0, @@ -10335,6 +10398,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -10360,6 +10424,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", + "notes": [], "params": { "addressableAreaName": "movableTrashB3", "alternateDropLocation": true, @@ -10382,12 +10447,14 @@ }, { "commandType": "dropTipInPlace", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "pickUpTip", + "notes": [], "params": { "wellLocation": { "offset": { @@ -10413,6 +10480,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -10438,6 +10506,7 @@ }, { "commandType": "touchTip", + "notes": [], "params": { "radius": 1.0, "speed": 60.0, @@ -10462,6 +10531,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -10487,6 +10557,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", + "notes": [], "params": { "addressableAreaName": "movableTrashB3", "alternateDropLocation": true, @@ -10509,12 +10580,14 @@ }, { "commandType": "dropTipInPlace", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "pickUpTip", + "notes": [], "params": { "wellLocation": { "offset": { @@ -10540,6 +10613,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -10565,6 +10639,7 @@ }, { "commandType": "touchTip", + "notes": [], "params": { "radius": 1.0, "speed": 60.0, @@ -10589,6 +10664,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -10614,6 +10690,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", + "notes": [], "params": { "addressableAreaName": "movableTrashB3", "alternateDropLocation": true, @@ -10636,12 +10713,14 @@ }, { "commandType": "dropTipInPlace", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "pickUpTip", + "notes": [], "params": { "wellLocation": { "offset": { @@ -10667,6 +10746,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -10692,6 +10772,7 @@ }, { "commandType": "touchTip", + "notes": [], "params": { "radius": 1.0, "speed": 60.0, @@ -10716,6 +10797,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -10741,6 +10823,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", + "notes": [], "params": { "addressableAreaName": "movableTrashB3", "alternateDropLocation": true, @@ -10763,12 +10846,14 @@ }, { "commandType": "dropTipInPlace", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "pickUpTip", + "notes": [], "params": { "wellLocation": { "offset": { @@ -10794,6 +10879,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -10819,6 +10905,7 @@ }, { "commandType": "touchTip", + "notes": [], "params": { "radius": 1.0, "speed": 60.0, @@ -10843,6 +10930,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -10868,6 +10956,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", + "notes": [], "params": { "addressableAreaName": "movableTrashB3", "alternateDropLocation": true, @@ -10890,12 +10979,14 @@ }, { "commandType": "dropTipInPlace", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "gripperWasteChute" @@ -10907,6 +10998,7 @@ }, { "commandType": "configureNozzleLayout", + "notes": [], "params": { "configurationParams": { "style": "ALL" @@ -10917,6 +11009,7 @@ }, { "commandType": "pickUpTip", + "notes": [], "params": { "wellLocation": { "offset": { @@ -10942,6 +11035,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -10967,6 +11061,7 @@ }, { "commandType": "touchTip", + "notes": [], "params": { "radius": 1.0, "speed": 60.0, @@ -10991,6 +11086,7 @@ }, { "commandType": "moveToWell", + "notes": [], "params": { "forceDirect": false, "wellLocation": { @@ -11014,6 +11110,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 995.0, @@ -11039,6 +11136,7 @@ }, { "commandType": "moveToAddressableArea", + "notes": [], "params": { "addressableAreaName": "96ChannelWasteChute", "forceDirect": false, @@ -11060,6 +11158,7 @@ }, { "commandType": "blowOutInPlace", + "notes": [], "params": { "flowRate": 80.0 }, @@ -11068,6 +11167,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -11093,6 +11193,7 @@ }, { "commandType": "touchTip", + "notes": [], "params": { "radius": 1.0, "speed": 60.0, @@ -11117,6 +11218,7 @@ }, { "commandType": "moveToWell", + "notes": [], "params": { "forceDirect": false, "wellLocation": { @@ -11140,6 +11242,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 995.0, @@ -11165,6 +11268,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", + "notes": [], "params": { "addressableAreaName": "movableTrashB3", "alternateDropLocation": false, @@ -11187,6 +11291,7 @@ }, { "commandType": "blowOutInPlace", + "notes": [], "params": { "flowRate": 80.0 }, @@ -11195,6 +11300,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 10.0, @@ -11220,6 +11326,7 @@ }, { "commandType": "touchTip", + "notes": [], "params": { "radius": 1.0, "speed": 60.0, @@ -11244,6 +11351,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "volume": 10.0, @@ -11269,6 +11377,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 15.0, @@ -11294,6 +11403,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "pushOut": 0.0, @@ -11320,6 +11430,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 15.0, @@ -11345,6 +11456,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "pushOut": 0.0, @@ -11371,6 +11483,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 15.0, @@ -11396,6 +11509,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "pushOut": 0.0, @@ -11422,6 +11536,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 15.0, @@ -11447,6 +11562,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "pushOut": 0.0, @@ -11473,6 +11589,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 15.0, @@ -11498,6 +11615,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "volume": 15.0, @@ -11523,6 +11641,7 @@ }, { "commandType": "dropTip", + "notes": [], "params": { "alternateDropLocation": false, "wellLocation": { @@ -11546,6 +11665,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "gripperWasteChute" @@ -11557,6 +11677,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -11566,6 +11687,7 @@ }, { "commandType": "pickUpTip", + "notes": [], "params": { "wellLocation": { "offset": { @@ -11591,6 +11713,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -11616,6 +11739,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "pushOut": 0.0, @@ -11642,6 +11766,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -11667,6 +11792,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "pushOut": 0.0, @@ -11693,6 +11819,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -11718,6 +11845,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -11743,6 +11871,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 10.0, @@ -11768,6 +11897,7 @@ }, { "commandType": "touchTip", + "notes": [], "params": { "radius": 1.0, "speed": 60.0, @@ -11792,6 +11922,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "volume": 10.0, @@ -11817,6 +11948,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -11842,6 +11974,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "volume": 5.0, @@ -11867,6 +12000,7 @@ }, { "commandType": "touchTip", + "notes": [], "params": { "radius": 1.0, "speed": 60.0, @@ -11891,6 +12025,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", + "notes": [], "params": { "addressableAreaName": "movableTrashB3", "alternateDropLocation": false, @@ -11913,6 +12048,7 @@ }, { "commandType": "blowOutInPlace", + "notes": [], "params": { "flowRate": 80.0 }, @@ -11921,6 +12057,7 @@ }, { "commandType": "dropTip", + "notes": [], "params": { "alternateDropLocation": false, "wellLocation": { @@ -11944,6 +12081,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "gripperWasteChute" @@ -11955,6 +12093,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "B2" @@ -11966,6 +12105,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -11977,6 +12117,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "B2" @@ -11988,6 +12129,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -11999,6 +12141,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -12010,6 +12153,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -12021,6 +12165,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -12032,6 +12177,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -12043,6 +12189,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "C4" @@ -12054,6 +12201,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -12065,6 +12213,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -12076,6 +12225,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -12087,6 +12237,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "C4" @@ -12098,6 +12249,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -12109,6 +12261,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -12120,6 +12273,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12129,6 +12283,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -12140,6 +12295,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12149,6 +12305,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -12160,6 +12317,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12169,6 +12327,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -12180,6 +12339,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12189,6 +12349,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -12200,6 +12361,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12209,6 +12371,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12218,6 +12381,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12227,6 +12391,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12236,6 +12401,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -12247,6 +12413,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -12258,6 +12425,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "B2" @@ -12269,6 +12437,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -12280,6 +12449,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -12291,6 +12461,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -12302,6 +12473,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "B2" @@ -12313,6 +12485,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -12324,6 +12497,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -12335,6 +12509,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "C4" @@ -12346,6 +12521,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -12357,6 +12533,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -12368,6 +12545,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -12379,6 +12557,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "C4" @@ -12390,6 +12569,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -12401,6 +12581,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -12412,6 +12593,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12421,6 +12603,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -12432,6 +12615,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12441,6 +12625,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -12452,6 +12637,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12461,6 +12647,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -12472,6 +12659,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12481,6 +12669,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -12492,6 +12681,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12501,6 +12691,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12510,6 +12701,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12519,6 +12711,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12528,6 +12721,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -12539,6 +12733,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -12550,6 +12745,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -12561,6 +12757,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -12572,6 +12769,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "B2" @@ -12583,6 +12781,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -12594,6 +12793,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -12605,6 +12805,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "B2" @@ -12616,6 +12817,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -12627,6 +12829,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -12638,6 +12841,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -12649,6 +12853,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -12660,6 +12865,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -12671,6 +12877,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "C4" @@ -12682,6 +12889,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -12693,6 +12901,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "C4" @@ -12704,6 +12913,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -12715,6 +12925,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12724,6 +12935,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -12735,6 +12947,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12744,6 +12957,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -12755,6 +12969,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12764,6 +12979,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -12775,6 +12991,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12784,6 +13001,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -12795,6 +13013,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12804,6 +13023,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12813,6 +13033,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12822,6 +13043,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12831,6 +13053,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -12842,6 +13065,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12851,6 +13075,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -12862,6 +13087,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12871,6 +13097,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "B2" @@ -12882,6 +13109,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12891,6 +13119,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -12902,6 +13131,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "B2" @@ -12913,6 +13143,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12922,6 +13153,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -12933,6 +13165,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12942,6 +13175,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -12953,6 +13187,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12962,6 +13197,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "C4" @@ -12973,6 +13209,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -12982,6 +13219,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -12993,6 +13231,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13002,6 +13241,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "C4" @@ -13013,6 +13253,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -13024,6 +13265,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13033,6 +13275,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13042,6 +13285,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13051,6 +13295,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13060,6 +13305,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13069,6 +13315,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13078,6 +13325,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13087,6 +13335,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13096,6 +13345,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13105,6 +13355,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13114,6 +13365,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13123,6 +13375,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13132,6 +13385,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -13143,6 +13397,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13152,6 +13407,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "B2" @@ -13163,6 +13419,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13172,6 +13429,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -13183,6 +13441,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "B2" @@ -13194,6 +13453,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13203,6 +13463,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -13214,6 +13475,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13223,6 +13485,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -13234,6 +13497,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13243,6 +13507,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "C4" @@ -13254,6 +13519,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13263,6 +13529,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -13274,6 +13541,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13283,6 +13551,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "C4" @@ -13294,6 +13563,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -13305,6 +13575,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13314,6 +13585,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13323,6 +13595,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13332,6 +13605,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13341,6 +13615,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13350,6 +13625,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13359,6 +13635,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13368,6 +13645,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13377,6 +13655,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13386,6 +13665,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13395,6 +13675,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13404,6 +13685,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13413,6 +13695,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -13424,6 +13707,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13433,6 +13717,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "B2" @@ -13444,6 +13729,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13453,6 +13739,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -13464,6 +13751,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "B2" @@ -13475,6 +13763,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13484,6 +13773,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -13495,6 +13785,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13504,6 +13795,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -13515,6 +13807,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13524,6 +13817,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "C4" @@ -13535,6 +13829,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13544,6 +13839,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -13555,6 +13851,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13564,6 +13861,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "C4" @@ -13575,6 +13873,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -13586,6 +13885,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13595,6 +13895,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13604,6 +13905,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13613,6 +13915,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13622,6 +13925,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13631,6 +13935,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13640,6 +13945,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13649,6 +13955,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13658,6 +13965,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13667,6 +13975,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13676,6 +13985,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13685,6 +13995,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13694,6 +14005,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -13705,6 +14017,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13714,6 +14027,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "B2" @@ -13725,6 +14039,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13734,6 +14049,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C2" @@ -13745,6 +14061,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "B2" @@ -13756,6 +14073,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13765,6 +14083,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -13776,6 +14095,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13785,6 +14105,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "slotName": "C3" @@ -13796,6 +14117,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13805,6 +14127,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "C4" @@ -13816,6 +14139,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13825,6 +14149,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -13836,6 +14161,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13845,6 +14171,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "C4" @@ -13856,6 +14183,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -13867,6 +14195,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13876,6 +14205,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13885,6 +14215,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13894,6 +14225,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13903,6 +14235,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13912,6 +14245,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13921,6 +14255,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13930,6 +14265,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13939,6 +14275,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13948,6 +14285,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13957,6 +14295,7 @@ }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": {}, "strategy": "usingGripper" @@ -13966,12 +14305,14 @@ }, { "commandType": "thermocycler/closeLid", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "thermocycler/setTargetBlockTemperature", + "notes": [], "params": { "celsius": 75.0, "holdTimeSeconds": 5.0 @@ -13983,12 +14324,14 @@ }, { "commandType": "thermocycler/waitForBlockTemperature", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "thermocycler/setTargetLidTemperature", + "notes": [], "params": { "celsius": 80.0 }, @@ -13999,24 +14342,28 @@ }, { "commandType": "thermocycler/waitForLidTemperature", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "thermocycler/deactivateBlock", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "thermocycler/deactivateLid", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "heaterShaker/openLabwareLatch", + "notes": [], "params": {}, "result": { "pipetteRetracted": true @@ -14025,12 +14372,14 @@ }, { "commandType": "heaterShaker/closeLabwareLatch", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "heaterShaker/setTargetTemperature", + "notes": [], "params": { "celsius": 75.0 }, @@ -14039,6 +14388,7 @@ }, { "commandType": "heaterShaker/setAndWaitForShakeSpeed", + "notes": [], "params": { "rpm": 1000.0 }, @@ -14049,24 +14399,28 @@ }, { "commandType": "heaterShaker/waitForTemperature", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "heaterShaker/deactivateHeater", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "heaterShaker/deactivateShaker", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "temperatureModule/setTargetTemperature", + "notes": [], "params": { "celsius": 80.0 }, @@ -14077,12 +14431,14 @@ }, { "commandType": "temperatureModule/waitForTemperature", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "temperatureModule/setTargetTemperature", + "notes": [], "params": { "celsius": 10.0 }, @@ -14093,18 +14449,21 @@ }, { "commandType": "temperatureModule/waitForTemperature", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "temperatureModule/deactivate", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "moveLabware", + "notes": [], "params": { "newLocation": { "addressableAreaName": "D4" @@ -14125,7 +14484,7 @@ "errors": [], "files": [ { - "name": "Flex_P1000_96_Gripper_2_16_TriggerPrepareForMountMovement.py", + "name": "Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_TriggerPrepareForMountMovement.py", "role": "main" }, { @@ -14238,5 +14597,6 @@ "pipetteName": "p1000_96" } ], - "robotType": "OT-3 Standard" + "robotType": "OT-3 Standard", + "runTimeParameters": [] } diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a08dfa462f][OT2_P300SLeft_MM1_MM_2_2_EngageMagHeightFromBase].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[3251c6e175][OT2_S_v2_2_P300S_None_MM1_MM2_EngageMagHeightFromBase].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a08dfa462f][OT2_P300SLeft_MM1_MM_2_2_EngageMagHeightFromBase].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[3251c6e175][OT2_S_v2_2_P300S_None_MM1_MM2_EngageMagHeightFromBase].json index 1f5fb20889a..12e563ee366 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a08dfa462f][OT2_P300SLeft_MM1_MM_2_2_EngageMagHeightFromBase].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[3251c6e175][OT2_S_v2_2_P300S_None_MM1_MM2_EngageMagHeightFromBase].json @@ -1519,7 +1519,7 @@ "errors": [], "files": [ { - "name": "OT2_P300SLeft_MM1_MM_2_2_EngageMagHeightFromBase.py", + "name": "OT2_S_v2_2_P300S_None_MM1_MM2_EngageMagHeightFromBase.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[33db294a9b][Flex_X_v2_18_NO_PIPETTES_DescriptionTooLongRTP].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[33db294a9b][Flex_X_v2_18_NO_PIPETTES_DescriptionTooLongRTP].json new file mode 100644 index 00000000000..a61a4a011ff --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[33db294a9b][Flex_X_v2_18_NO_PIPETTES_DescriptionTooLongRTP].json @@ -0,0 +1,75 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable dilutions has value 1", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + } + ], + "config": { + "apiVersion": [ + 2, + 18 + ], + "protocolType": "python" + }, + "errors": [], + "files": [ + { + "name": "Flex_X_v2_18_NO_PIPETTES_DescriptionTooLongRTP.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "protocolName": "Description too long" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-3 Standard", + "runTimeParameters": [ + { + "default": 1.0, + "description": "This is a description that is longer than 30 characters.", + "displayName": "display name", + "max": 3.0, + "min": 1.0, + "type": "int", + "value": 1.0, + "variableName": "dilutions" + } + ] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[38b5298c77][Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultOutOfRangeRTP_Override_default_less_than_minimum].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[38b5298c77][Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultOutOfRangeRTP_Override_default_less_than_minimum].json new file mode 100644 index 00000000000..94b4b0ec4eb --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[38b5298c77][Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultOutOfRangeRTP_Override_default_less_than_minimum].json @@ -0,0 +1,74 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + } + ], + "config": { + "apiVersion": [ + 2, + 18 + ], + "protocolType": "python" + }, + "errors": [ + { + "detail": "ParameterValueError [line 32]: Parameter must be between 1 and 3 inclusive.", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ExceptionInProtocolError", + "wrappedErrors": [ + { + "detail": "opentrons.protocols.parameters.types.ParameterValueError: Parameter must be between 1 and 3 inclusive.", + "errorCode": "4000", + "errorInfo": { + "args": "('Parameter must be between 1 and 3 inclusive.',)", + "class": "ParameterValueError", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 80, in _parse_and_set_parameters\n exec(\"add_parameters(__param_context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultOutOfRangeRTP_Override_default_less_than_minimum.py\", line 32, in add_parameters\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/_parameter_context.py\", line 56, in add_int\n parameter = parameter_definition.create_int_parameter(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 178, in create_int_parameter\n return ParameterDefinition(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 84, in __init__\n self.value: ParamType = default\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 104, in value\n raise ParameterValueError(\n" + }, + "errorType": "PythonException", + "wrappedErrors": [] + } + ] + } + ], + "files": [ + { + "name": "Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultOutOfRangeRTP_Override_default_less_than_minimum.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "protocolName": "Default not in range" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-3 Standard", + "runTimeParameters": [] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[5fc4f3adbc][OT2_P20SRight_None_6_1_SimpleTransferError].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4389e3ab18][OT2_X_v6_P20S_None_SimpleTransfer].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[5fc4f3adbc][OT2_P20SRight_None_6_1_SimpleTransferError].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4389e3ab18][OT2_X_v6_P20S_None_SimpleTransfer].json index a5d379ba794..b4b8520bb3a 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[5fc4f3adbc][OT2_P20SRight_None_6_1_SimpleTransferError].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4389e3ab18][OT2_X_v6_P20S_None_SimpleTransfer].json @@ -1740,7 +1740,7 @@ ], "files": [ { - "name": "OT2_P20SRight_None_6_1_SimpleTransferError.json", + "name": "OT2_X_v6_P20S_None_SimpleTransfer.json", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4458220422][OT2_S_v2_18_NO_PIPETTES_GoldenRTP_OT2].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4458220422][OT2_S_v2_18_NO_PIPETTES_GoldenRTP_OT2].json new file mode 100644 index 00000000000..0037466294b --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4458220422][OT2_S_v2_18_NO_PIPETTES_GoldenRTP_OT2].json @@ -0,0 +1,534 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable min_max_all_fields has value 6", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable int_min_max_without_unit has value 1", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable int_min_max_without_description has value 1", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable int_min_max_without_unit_and_description has value 1", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable int_choices_all_fields has value 20", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable int_choice_no_unit has value 6", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable int_choice_no_unit_desc has value 10", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable float_min_max_all_fields has value 30.0", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable float_min_max_no_unit has value 1.8", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable float_min_max_no_unit_or_desc has value 1.8", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable float_choices_all_fields has value 20.0", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable float_choices_no_unit has value 10.0", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable float_choices_no_description has value 20.0", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable float_choices_no_unit_or_desc has value 20.0", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable bool_all_fields has value False", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable bool_no_desc has value False", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable str_choices_all_fields has value flex_1channel_50", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable str_choices_all_many_fields has value E", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable str_choices_no_desc has value flex_1channel_50", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + } + ], + "config": { + "apiVersion": [ + 2, + 18 + ], + "protocolType": "python" + }, + "errors": [], + "files": [ + { + "name": "OT2_S_v2_18_NO_PIPETTES_GoldenRTP_OT2.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "protocolName": "Golden RTP Examples OT2" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-2 Standard", + "runTimeParameters": [ + { + "default": 6.0, + "description": "Reused description for all parameters.", + "displayName": "int min/max all", + "max": 12.0, + "min": 1.0, + "suffix": "unit", + "type": "int", + "value": 6.0, + "variableName": "min_max_all_fields" + }, + { + "default": 1.0, + "description": "Reused description for all parameters.", + "displayName": "int min/max no unit", + "max": 3.0, + "min": 1.0, + "type": "int", + "value": 1.0, + "variableName": "int_min_max_without_unit" + }, + { + "default": 1.0, + "displayName": "int min/max no description", + "max": 3.0, + "min": 1.0, + "suffix": "unit", + "type": "int", + "value": 1.0, + "variableName": "int_min_max_without_description" + }, + { + "default": 1.0, + "displayName": "int min/max no unit,desc", + "max": 3.0, + "min": 1.0, + "type": "int", + "value": 1.0, + "variableName": "int_min_max_without_unit_and_description" + }, + { + "choices": [ + { + "displayName": "20", + "value": 20.0 + }, + { + "displayName": "16", + "value": 16.0 + } + ], + "default": 20.0, + "description": "Reused description for all parameters.", + "displayName": "int choices all", + "type": "int", + "value": 20.0, + "variableName": "int_choices_all_fields" + }, + { + "choices": [ + { + "displayName": "1X", + "value": 6.0 + }, + { + "displayName": "2X", + "value": 12.0 + } + ], + "default": 6.0, + "description": "Reused description for all parameters.", + "displayName": "int choice no unit", + "type": "int", + "value": 6.0, + "variableName": "int_choice_no_unit" + }, + { + "choices": [ + { + "displayName": "10X", + "value": 10.0 + }, + { + "displayName": "100X", + "value": 100.0 + } + ], + "default": 10.0, + "displayName": "int choice no unit, desc", + "type": "int", + "value": 10.0, + "variableName": "int_choice_no_unit_desc" + }, + { + "default": 30.0, + "description": "Reused description for all parameters.", + "displayName": "float min/max all fields", + "max": 30.0, + "min": 20.0, + "suffix": "unit", + "type": "float", + "value": 30.0, + "variableName": "float_min_max_all_fields" + }, + { + "default": 1.8, + "description": "Reused description for all parameters.", + "displayName": "float min/max no unit", + "max": 3.0, + "min": 1.5, + "type": "float", + "value": 1.8, + "variableName": "float_min_max_no_unit" + }, + { + "default": 1.8, + "displayName": "float min/max no unit,desc", + "max": 3.0, + "min": 1.5, + "type": "float", + "value": 1.8, + "variableName": "float_min_max_no_unit_or_desc" + }, + { + "choices": [ + { + "displayName": "Low Volume (10.0µL)", + "value": 10.0 + }, + { + "displayName": "Medium Volume (20.0µL)", + "value": 20.0 + }, + { + "displayName": "High Volume (50.0µL)", + "value": 50.0 + } + ], + "default": 20.0, + "description": "Reused description for all parameters.", + "displayName": "float choices all", + "type": "float", + "value": 20.0, + "variableName": "float_choices_all_fields" + }, + { + "choices": [ + { + "displayName": "Low Volume (10.0µL)", + "value": 10.0 + }, + { + "displayName": "High Volume (50.0µL)", + "value": 50.0 + } + ], + "default": 10.0, + "description": "Reused description for all parameters.", + "displayName": "float choices no unit", + "type": "float", + "value": 10.0, + "variableName": "float_choices_no_unit" + }, + { + "choices": [ + { + "displayName": "Low Volume (10.0µL)", + "value": 10.0 + }, + { + "displayName": "Medium Volume (20.0µL)", + "value": 20.0 + }, + { + "displayName": "High Volume (50.0µL)", + "value": 50.0 + } + ], + "default": 20.0, + "displayName": "float choices no description", + "type": "float", + "value": 20.0, + "variableName": "float_choices_no_description" + }, + { + "choices": [ + { + "displayName": "Low Volume (10.0µL)", + "value": 10.0 + }, + { + "displayName": "Medium Volume (20.0µL)", + "value": 20.0 + }, + { + "displayName": "High Volume (50.0µL)", + "value": 50.0 + } + ], + "default": 20.0, + "displayName": "float choices no unit,desc", + "type": "float", + "value": 20.0, + "variableName": "float_choices_no_unit_or_desc" + }, + { + "default": false, + "description": "When on, skip aspirate and dispense steps.", + "displayName": "bool all fields", + "type": "bool", + "value": false, + "variableName": "bool_all_fields" + }, + { + "default": false, + "displayName": "bool no description", + "type": "bool", + "value": false, + "variableName": "bool_no_desc" + }, + { + "choices": [ + { + "displayName": "Single channel 50µL", + "value": "flex_1channel_50" + }, + { + "displayName": "Eight Channel 50µL", + "value": "flex_8channel_50" + } + ], + "default": "flex_1channel_50", + "description": "What pipette to use during the protocol.", + "displayName": "str choices all", + "type": "str", + "value": "flex_1channel_50", + "variableName": "str_choices_all_fields" + }, + { + "choices": [ + { + "displayName": "A", + "value": "A" + }, + { + "displayName": "B", + "value": "B" + }, + { + "displayName": "C", + "value": "C" + }, + { + "displayName": "D", + "value": "D" + }, + { + "displayName": "E", + "value": "E" + }, + { + "displayName": "F", + "value": "F" + } + ], + "default": "E", + "description": "Reused description for all parameters.", + "displayName": "str choices all many", + "type": "str", + "value": "E", + "variableName": "str_choices_all_many_fields" + }, + { + "choices": [ + { + "displayName": "Single channel 50µL", + "value": "flex_1channel_50" + }, + { + "displayName": "Eight Channel 50µL", + "value": "flex_8channel_50" + } + ], + "default": "flex_1channel_50", + "displayName": "str choices no desc", + "type": "str", + "value": "flex_1channel_50", + "variableName": "str_choices_no_desc" + } + ] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a23a1de3ce][OT2_P300M_P20S_TC_HS_TM_2_16_SmokeTestV3].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4a82419f1f][OT2_S_v2_16_P300M_P20S_HS_TC_TM_SmokeTestV3].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a23a1de3ce][OT2_P300M_P20S_TC_HS_TM_2_16_SmokeTestV3].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4a82419f1f][OT2_S_v2_16_P300M_P20S_HS_TC_TM_SmokeTestV3].json index 01832c02dce..22da4b6635a 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a23a1de3ce][OT2_P300M_P20S_TC_HS_TM_2_16_SmokeTestV3].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4a82419f1f][OT2_S_v2_16_P300M_P20S_HS_TC_TM_SmokeTestV3].json @@ -15549,7 +15549,7 @@ "errors": [], "files": [ { - "name": "OT2_P300M_P20S_TC_HS_TM_2_16_SmokeTestV3.py", + "name": "OT2_S_v2_16_P300M_P20S_HS_TC_TM_SmokeTestV3.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[b20d3ccf8f][OT2_P300M_P20S_TC_HS_TM_2_17_dispense_changes].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4b17883f74][OT2_S_v2_17_P300M_P20S_HS_TC_TM_dispense_changes].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[b20d3ccf8f][OT2_P300M_P20S_TC_HS_TM_2_17_dispense_changes].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4b17883f74][OT2_S_v2_17_P300M_P20S_HS_TC_TM_dispense_changes].json index c6a45057ed3..4fb35baadae 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[b20d3ccf8f][OT2_P300M_P20S_TC_HS_TM_2_17_dispense_changes].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4b17883f74][OT2_S_v2_17_P300M_P20S_HS_TC_TM_dispense_changes].json @@ -2988,7 +2988,7 @@ ], "files": [ { - "name": "OT2_P300M_P20S_TC_HS_TM_2_17_dispense_changes.py", + "name": "OT2_S_v2_17_P300M_P20S_HS_TC_TM_dispense_changes.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4cb705bdbf][Flex_X_v2_16_NO_PIPETTES_MM_MagneticModuleInFlexProtocol].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4cb705bdbf][Flex_X_v2_16_NO_PIPETTES_MM_MagneticModuleInFlexProtocol].json new file mode 100644 index 00000000000..1f2a502c2ab --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4cb705bdbf][Flex_X_v2_16_NO_PIPETTES_MM_MagneticModuleInFlexProtocol].json @@ -0,0 +1,105 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "loadModule", + "error": { + "detail": "ValueError: Module Type magneticModuleType does not have a related fixture ID.", + "errorCode": "4000", + "errorInfo": { + "args": "('Module Type magneticModuleType does not have a related fixture ID.',)", + "class": "ValueError", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/execution/command_executor.py\", line 150, in execute\n result: CommandResult = await command_impl.execute(running_command.params) # type: ignore[arg-type]\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/commands/load_module.py\", line 116, in execute\n self._ensure_module_location(params.location.slotName, module_type)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/commands/load_module.py\", line 167, in _ensure_module_location\n cutout_fixture_id = ModuleType.to_module_fixture_id(module_type)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/hardware_control/modules/types.py\", line 79, in to_module_fixture_id\n raise ValueError(\n" + }, + "errorType": "PythonException", + "wrappedErrors": [] + }, + "notes": [], + "params": { + "location": { + "slotName": "C1" + }, + "model": "magneticModuleV2" + }, + "status": "failed" + } + ], + "config": { + "apiVersion": [ + 2, + 16 + ], + "protocolType": "python" + }, + "errors": [ + { + "detail": "ProtocolCommandFailedError [line 15]: Error 4000 GENERAL_ERROR (ProtocolCommandFailedError): PythonException: ValueError: Module Type magneticModuleType does not have a related fixture ID.", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ExceptionInProtocolError", + "wrappedErrors": [ + { + "detail": "PythonException: ValueError: Module Type magneticModuleType does not have a related fixture ID.", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ProtocolCommandFailedError", + "wrappedErrors": [ + { + "detail": "ValueError: Module Type magneticModuleType does not have a related fixture ID.", + "errorCode": "4000", + "errorInfo": { + "args": "('Module Type magneticModuleType does not have a related fixture ID.',)", + "class": "ValueError", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/execution/command_executor.py\", line 150, in execute\n result: CommandResult = await command_impl.execute(running_command.params) # type: ignore[arg-type]\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/commands/load_module.py\", line 116, in execute\n self._ensure_module_location(params.location.slotName, module_type)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/commands/load_module.py\", line 167, in _ensure_module_location\n cutout_fixture_id = ModuleType.to_module_fixture_id(module_type)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/hardware_control/modules/types.py\", line 79, in to_module_fixture_id\n raise ValueError(\n" + }, + "errorType": "PythonException", + "wrappedErrors": [] + } + ] + } + ] + } + ], + "files": [ + { + "name": "Flex_X_v2_16_NO_PIPETTES_MM_MagneticModuleInFlexProtocol.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "author": "Derek Maggio ", + "protocolName": "QA Protocol - Analysis Error - Magnetic Module in Flex Protocol" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-3 Standard", + "runTimeParameters": [] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4fadc166c0][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_variable_name].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4fadc166c0][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_variable_name].json new file mode 100644 index 00000000000..b41923a6a2d --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4fadc166c0][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_variable_name].json @@ -0,0 +1,74 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + } + ], + "config": { + "apiVersion": [ + 2, + 18 + ], + "protocolType": "python" + }, + "errors": [ + { + "detail": "ParameterNameError [line 39]: Variable name must be a string.", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ExceptionInProtocolError", + "wrappedErrors": [ + { + "detail": "opentrons.protocols.parameters.types.ParameterNameError: Variable name must be a string.", + "errorCode": "4000", + "errorInfo": { + "args": "('Variable name must be a string.',)", + "class": "ParameterNameError", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 80, in _parse_and_set_parameters\n exec(\"add_parameters(__param_context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_variable_name.py\", line 39, in add_parameters\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/_parameter_context.py\", line 93, in add_float\n parameter = parameter_definition.create_float_parameter(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 202, in create_float_parameter\n return ParameterDefinition(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 57, in __init__\n self._variable_name = validation.ensure_variable_name(variable_name)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/validation.py\", line 46, in ensure_variable_name\n raise ParameterNameError(\"Variable name must be a string.\")\n" + }, + "errorType": "PythonException", + "wrappedErrors": [] + } + ] + } + ], + "files": [ + { + "name": "Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_variable_name.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "protocolName": "Description Too Long 2.18" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-3 Standard", + "runTimeParameters": [] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[51a761307d][Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultOutOfRangeRTP_Override_default_greater_than_maximum].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[51a761307d][Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultOutOfRangeRTP_Override_default_greater_than_maximum].json new file mode 100644 index 00000000000..b54f76e6b5f --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[51a761307d][Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultOutOfRangeRTP_Override_default_greater_than_maximum].json @@ -0,0 +1,74 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + } + ], + "config": { + "apiVersion": [ + 2, + 18 + ], + "protocolType": "python" + }, + "errors": [ + { + "detail": "ParameterValueError [line 23]: Parameter must be between 1 and 3 inclusive.", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ExceptionInProtocolError", + "wrappedErrors": [ + { + "detail": "opentrons.protocols.parameters.types.ParameterValueError: Parameter must be between 1 and 3 inclusive.", + "errorCode": "4000", + "errorInfo": { + "args": "('Parameter must be between 1 and 3 inclusive.',)", + "class": "ParameterValueError", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 80, in _parse_and_set_parameters\n exec(\"add_parameters(__param_context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultOutOfRangeRTP_Override_default_greater_than_maximum.py\", line 23, in add_parameters\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/_parameter_context.py\", line 56, in add_int\n parameter = parameter_definition.create_int_parameter(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 178, in create_int_parameter\n return ParameterDefinition(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 84, in __init__\n self.value: ParamType = default\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 104, in value\n raise ParameterValueError(\n" + }, + "errorType": "PythonException", + "wrappedErrors": [] + } + ] + } + ], + "files": [ + { + "name": "Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultOutOfRangeRTP_Override_default_greater_than_maximum.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "protocolName": "Default not in range" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-3 Standard", + "runTimeParameters": [] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[5fa61df9e2][OT2_P300M_P20S_NoMod_6_1_MixTransferManyLiquids].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[51fc977577][OT2_S_v6_P300M_P20S_MixTransferManyLiquids].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[5fa61df9e2][OT2_P300M_P20S_NoMod_6_1_MixTransferManyLiquids].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[51fc977577][OT2_S_v6_P300M_P20S_MixTransferManyLiquids].json index a3065f29fa7..eb584b67d86 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[5fa61df9e2][OT2_P300M_P20S_NoMod_6_1_MixTransferManyLiquids].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[51fc977577][OT2_S_v6_P300M_P20S_MixTransferManyLiquids].json @@ -5250,7 +5250,7 @@ "errors": [], "files": [ { - "name": "OT2_P300M_P20S_NoMod_6_1_MixTransferManyLiquids.json", + "name": "OT2_S_v6_P300M_P20S_MixTransferManyLiquids.json", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6b0e10c81f][OT2_P300S_None_2_16_verifyNoFloatingPointErrorInPipetting].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[54f717cfd1][OT2_S_v2_16_P300S_None_verifyNoFloatingPointErrorInPipetting].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6b0e10c81f][OT2_P300S_None_2_16_verifyNoFloatingPointErrorInPipetting].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[54f717cfd1][OT2_S_v2_16_P300S_None_verifyNoFloatingPointErrorInPipetting].json index 66b3e6cd601..7a72c2ac8a8 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6b0e10c81f][OT2_P300S_None_2_16_verifyNoFloatingPointErrorInPipetting].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[54f717cfd1][OT2_S_v2_16_P300S_None_verifyNoFloatingPointErrorInPipetting].json @@ -1769,7 +1769,7 @@ "errors": [], "files": [ { - "name": "OT2_P300S_None_2_16_verifyNoFloatingPointErrorInPipetting.py", + "name": "OT2_S_v2_16_P300S_None_verifyNoFloatingPointErrorInPipetting.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[ac35bb394d][Flex_None_None_2_16_AnalysisError_TrashBinInStagingAreaCol4].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[58750bf5fb][Flex_X_v2_16_NO_PIPETTES_TrashBinInStagingAreaCol4].json similarity index 75% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[ac35bb394d][Flex_None_None_2_16_AnalysisError_TrashBinInStagingAreaCol4].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[58750bf5fb][Flex_X_v2_16_NO_PIPETTES_TrashBinInStagingAreaCol4].json index 4beea85705a..c123a9162fc 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[ac35bb394d][Flex_None_None_2_16_AnalysisError_TrashBinInStagingAreaCol4].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[58750bf5fb][Flex_X_v2_16_NO_PIPETTES_TrashBinInStagingAreaCol4].json @@ -28,7 +28,7 @@ "errorInfo": { "args": "('Staging areas not permitted for trash bin.',)", "class": "ValueError", - "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_None_None_2_16_AnalysisError_TrashBinInStagingAreaCol4.py\", line 15, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line 383, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/protocol_context.py\", line 512, in load_trash_bin\n raise ValueError(\"Staging areas not permitted for trash bin.\")\n" + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_X_v2_16_NO_PIPETTES_TrashBinInStagingAreaCol4.py\", line 15, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line 383, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/protocol_context.py\", line 512, in load_trash_bin\n raise ValueError(\"Staging areas not permitted for trash bin.\")\n" }, "errorType": "PythonException", "wrappedErrors": [] @@ -38,7 +38,7 @@ ], "files": [ { - "name": "Flex_None_None_2_16_AnalysisError_TrashBinInStagingAreaCol4.py", + "name": "Flex_X_v2_16_NO_PIPETTES_TrashBinInStagingAreaCol4.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[3369b24214][Flex_P300Gen2_None_2_16_AnalysisError_OT2PipetteInFlexProtocol].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[5e958b7c98][Flex_X_v2_16_P300MGen2_None_OT2PipetteInFlexProtocol].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[3369b24214][Flex_P300Gen2_None_2_16_AnalysisError_OT2PipetteInFlexProtocol].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[5e958b7c98][Flex_X_v2_16_P300MGen2_None_OT2PipetteInFlexProtocol].json index f0b422e26bf..946f02f66fb 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[3369b24214][Flex_P300Gen2_None_2_16_AnalysisError_OT2PipetteInFlexProtocol].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[5e958b7c98][Flex_X_v2_16_P300MGen2_None_OT2PipetteInFlexProtocol].json @@ -1205,7 +1205,7 @@ ], "files": [ { - "name": "Flex_P300Gen2_None_2_16_AnalysisError_OT2PipetteInFlexProtocol.py", + "name": "Flex_X_v2_16_P300MGen2_None_OT2PipetteInFlexProtocol.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[60015c6e65][OT2_X_v2_18_None_None_duplicateRTPVariableName].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[60015c6e65][OT2_X_v2_18_None_None_duplicateRTPVariableName].json new file mode 100644 index 00000000000..477935caf3a --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[60015c6e65][OT2_X_v2_18_None_None_duplicateRTPVariableName].json @@ -0,0 +1,95 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + } + ], + "config": { + "apiVersion": [ + 2, + 18 + ], + "protocolType": "python" + }, + "errors": [ + { + "detail": "ParameterNameError [line 28]: \"variable_a\" is already defined as a variable name for another parameter. All variable names must be unique.", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ExceptionInProtocolError", + "wrappedErrors": [ + { + "detail": "opentrons.protocols.parameters.types.ParameterNameError: \"variable_a\" is already defined as a variable name for another parameter. All variable names must be unique.", + "errorCode": "4000", + "errorInfo": { + "args": "('\"variable_a\" is already defined as a variable name for another parameter. All variable names must be unique.',)", + "class": "ParameterNameError", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 80, in _parse_and_set_parameters\n exec(\"add_parameters(__param_context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"OT2_X_v2_18_None_None_duplicateRTPVariableName.py\", line 28, in add_parameters\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/_parameter_context.py\", line 55, in add_int\n validation.validate_variable_name_unique(variable_name, set(self._parameters))\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/validation.py\", line 24, in validate_variable_name_unique\n raise ParameterNameError(\n" + }, + "errorType": "PythonException", + "wrappedErrors": [] + } + ] + } + ], + "files": [ + { + "name": "OT2_X_v2_18_None_None_duplicateRTPVariableName.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "protocolName": "Multiple RTP Variables with Same Name" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-2 Standard", + "runTimeParameters": [ + { + "default": 1.0, + "description": "This is a description", + "displayName": "int 1", + "max": 3.0, + "min": 1.0, + "type": "int", + "value": 1.0, + "variableName": "variable_a" + }, + { + "default": 1.0, + "description": "This is a description", + "displayName": "int 2", + "max": 3.0, + "min": 1.0, + "type": "int", + "value": 1.0, + "variableName": "variable_b" + } + ] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[604023f7f1][Flex_X_v2_16_NO_PIPETTES_TM_ModuleInStagingAreaCol3].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[604023f7f1][Flex_X_v2_16_NO_PIPETTES_TM_ModuleInStagingAreaCol3].json new file mode 100644 index 00000000000..5555f2a39c9 --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[604023f7f1][Flex_X_v2_16_NO_PIPETTES_TM_ModuleInStagingAreaCol3].json @@ -0,0 +1,192 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "loadLabware", + "notes": [], + "params": { + "loadName": "nest_1_reservoir_290ml", + "location": { + "addressableAreaName": "C4" + }, + "namespace": "opentrons", + "version": 1 + }, + "result": { + "definition": { + "allowedRoles": [], + "brand": { + "brand": "NEST", + "brandId": [ + "360206", + "360266" + ], + "links": [ + "https://www.nest-biotech.com/reagent-reserviors" + ] + }, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + }, + "dimensions": { + "xDimension": 127.76, + "yDimension": 85.47, + "zDimension": 44.4 + }, + "gripperOffsets": {}, + "groups": [ + { + "metadata": { + "wellBottomShape": "v" + }, + "wells": [ + "A1" + ] + } + ], + "metadata": { + "displayCategory": "reservoir", + "displayName": "NEST 1 Well Reservoir 290 mL", + "displayVolumeUnits": "mL", + "tags": [] + }, + "namespace": "opentrons", + "ordering": [ + [ + "A1" + ] + ], + "parameters": { + "format": "trough", + "isMagneticModuleCompatible": false, + "isTiprack": false, + "loadName": "nest_1_reservoir_290ml", + "quirks": [ + "centerMultichannelOnWells", + "touchTipDisabled" + ] + }, + "schemaVersion": 2, + "stackingOffsetWithLabware": {}, + "stackingOffsetWithModule": {}, + "version": 1, + "wells": { + "A1": { + "depth": 39.55, + "shape": "rectangular", + "totalLiquidVolume": 290000, + "x": 63.88, + "xDimension": 106.8, + "y": 42.74, + "yDimension": 71.2, + "z": 4.85 + } + } + } + }, + "status": "succeeded" + }, + { + "commandType": "loadModule", + "error": { + "detail": "Cannot use Temperature Module in C3, not compatible with one or more of the following fixtures: Slot C4", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "IncompatibleAddressableAreaError", + "wrappedErrors": [] + }, + "notes": [], + "params": { + "location": { + "slotName": "C3" + }, + "model": "temperatureModuleV2" + }, + "status": "failed" + } + ], + "config": { + "apiVersion": [ + 2, + 16 + ], + "protocolType": "python" + }, + "errors": [ + { + "detail": "ProtocolCommandFailedError [line 17]: Error 4000 GENERAL_ERROR (ProtocolCommandFailedError): IncompatibleAddressableAreaError: Cannot use Temperature Module in C3, not compatible with one or more of the following fixtures: Slot C4", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ExceptionInProtocolError", + "wrappedErrors": [ + { + "detail": "IncompatibleAddressableAreaError: Cannot use Temperature Module in C3, not compatible with one or more of the following fixtures: Slot C4", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ProtocolCommandFailedError", + "wrappedErrors": [ + { + "detail": "Cannot use Temperature Module in C3, not compatible with one or more of the following fixtures: Slot C4", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "IncompatibleAddressableAreaError", + "wrappedErrors": [] + } + ] + } + ] + } + ], + "files": [ + { + "name": "Flex_X_v2_16_NO_PIPETTES_TM_ModuleInStagingAreaCol3.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [ + { + "definitionUri": "opentrons/nest_1_reservoir_290ml/1", + "loadName": "nest_1_reservoir_290ml", + "location": { + "addressableAreaName": "C4" + } + } + ], + "liquids": [], + "metadata": { + "author": "Derek Maggio ", + "protocolName": "QA Protocol - Analysis Error - Module in Staging Area Column 3" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-3 Standard", + "runTimeParameters": [] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[60c1d39463][Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultChoiceNoMatchChoice_Override_int_default_no_matching_choices].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[60c1d39463][Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultChoiceNoMatchChoice_Override_int_default_no_matching_choices].json new file mode 100644 index 00000000000..4670b2eed78 --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[60c1d39463][Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultChoiceNoMatchChoice_Override_int_default_no_matching_choices].json @@ -0,0 +1,74 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + } + ], + "config": { + "apiVersion": [ + 2, + 18 + ], + "protocolType": "python" + }, + "errors": [ + { + "detail": "ParameterValueError [line 24]: Parameter must be set to one of the allowed values of {9, 20, 15}.", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ExceptionInProtocolError", + "wrappedErrors": [ + { + "detail": "opentrons.protocols.parameters.types.ParameterValueError: Parameter must be set to one of the allowed values of {9, 20, 15}.", + "errorCode": "4000", + "errorInfo": { + "args": "('Parameter must be set to one of the allowed values of {9, 20, 15}.',)", + "class": "ParameterValueError", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 80, in _parse_and_set_parameters\n exec(\"add_parameters(__param_context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultChoiceNoMatchChoice_Override_int_default_no_matching_choices.py\", line 24, in add_parameters\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/_parameter_context.py\", line 56, in add_int\n parameter = parameter_definition.create_int_parameter(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 178, in create_int_parameter\n return ParameterDefinition(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 84, in __init__\n self.value: ParamType = default\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 95, in value\n raise ParameterValueError(\n" + }, + "errorType": "PythonException", + "wrappedErrors": [] + } + ] + } + ], + "files": [ + { + "name": "Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultChoiceNoMatchChoice_Override_int_default_no_matching_choices.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "protocolName": "default choice does not match a choice" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-3 Standard", + "runTimeParameters": [] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[512a897a47][Flex_None_None_TM_2_16_AnalysisError_ModuleInStagingAreaCol4].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6126498df7][Flex_X_v2_16_NO_PIPETTES_TM_ModuleInStagingAreaCol4].json similarity index 75% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[512a897a47][Flex_None_None_TM_2_16_AnalysisError_ModuleInStagingAreaCol4].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6126498df7][Flex_X_v2_16_NO_PIPETTES_TM_ModuleInStagingAreaCol4].json index ce2f5357e41..e8964ba8d4c 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[512a897a47][Flex_None_None_TM_2_16_AnalysisError_ModuleInStagingAreaCol4].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6126498df7][Flex_X_v2_16_NO_PIPETTES_TM_ModuleInStagingAreaCol4].json @@ -28,7 +28,7 @@ "errorInfo": { "args": "('Cannot load a module onto a staging slot.',)", "class": "ValueError", - "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_None_None_TM_2_16_AnalysisError_ModuleInStagingAreaCol4.py\", line 15, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line 383, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/protocol_context.py\", line 812, in load_module\n raise ValueError(\"Cannot load a module onto a staging slot.\")\n" + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_X_v2_16_NO_PIPETTES_TM_ModuleInStagingAreaCol4.py\", line 15, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line 383, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/protocol_context.py\", line 812, in load_module\n raise ValueError(\"Cannot load a module onto a staging slot.\")\n" }, "errorType": "PythonException", "wrappedErrors": [] @@ -38,7 +38,7 @@ ], "files": [ { - "name": "Flex_None_None_TM_2_16_AnalysisError_ModuleInStagingAreaCol4.py", + "name": "Flex_X_v2_16_NO_PIPETTES_TM_ModuleInStagingAreaCol4.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[61619d5498][Flex_S_v2_18_NO_PIPETTES_GoldenRTP].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[61619d5498][Flex_S_v2_18_NO_PIPETTES_GoldenRTP].json new file mode 100644 index 00000000000..73acba65566 --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[61619d5498][Flex_S_v2_18_NO_PIPETTES_GoldenRTP].json @@ -0,0 +1,534 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable min_max_all_fields has value 6", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable int_min_max_without_unit has value 1", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable int_min_max_without_description has value 1", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable int_min_max_without_unit_and_description has value 1", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable int_choices_all_fields has value 20", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable int_choice_no_unit has value 6", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable int_choice_no_unit_desc has value 10", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable float_min_max_all_fields has value 30.0", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable float_min_max_no_unit has value 1.8", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable float_min_max_no_unit_or_desc has value 1.8", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable float_choices_all_fields has value 20.0", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable float_choices_no_unit has value 10.0", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable float_choices_no_description has value 20.0", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable float_choices_no_unit_or_desc has value 20.0", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable bool_all_fields has value False", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable bool_no_desc has value False", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable str_choices_all_fields has value flex_1channel_50", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable str_choices_all_many_fields has value E", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable str_choices_no_desc has value flex_1channel_50", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + } + ], + "config": { + "apiVersion": [ + 2, + 18 + ], + "protocolType": "python" + }, + "errors": [], + "files": [ + { + "name": "Flex_S_v2_18_NO_PIPETTES_GoldenRTP.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "protocolName": "Golden RTP Examples" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-3 Standard", + "runTimeParameters": [ + { + "default": 6.0, + "description": "Reused description for all parameters.", + "displayName": "int min/max all", + "max": 12.0, + "min": 1.0, + "suffix": "unit", + "type": "int", + "value": 6.0, + "variableName": "min_max_all_fields" + }, + { + "default": 1.0, + "description": "Reused description for all parameters.", + "displayName": "int min/max no unit", + "max": 3.0, + "min": 1.0, + "type": "int", + "value": 1.0, + "variableName": "int_min_max_without_unit" + }, + { + "default": 1.0, + "displayName": "int min/max no description", + "max": 3.0, + "min": 1.0, + "suffix": "unit", + "type": "int", + "value": 1.0, + "variableName": "int_min_max_without_description" + }, + { + "default": 1.0, + "displayName": "int min/max no unit,desc", + "max": 3.0, + "min": 1.0, + "type": "int", + "value": 1.0, + "variableName": "int_min_max_without_unit_and_description" + }, + { + "choices": [ + { + "displayName": "20", + "value": 20.0 + }, + { + "displayName": "16", + "value": 16.0 + } + ], + "default": 20.0, + "description": "Reused description for all parameters.", + "displayName": "int choices all", + "type": "int", + "value": 20.0, + "variableName": "int_choices_all_fields" + }, + { + "choices": [ + { + "displayName": "1X", + "value": 6.0 + }, + { + "displayName": "2X", + "value": 12.0 + } + ], + "default": 6.0, + "description": "Reused description for all parameters.", + "displayName": "int choice no unit", + "type": "int", + "value": 6.0, + "variableName": "int_choice_no_unit" + }, + { + "choices": [ + { + "displayName": "10X", + "value": 10.0 + }, + { + "displayName": "100X", + "value": 100.0 + } + ], + "default": 10.0, + "displayName": "int choice no unit, desc", + "type": "int", + "value": 10.0, + "variableName": "int_choice_no_unit_desc" + }, + { + "default": 30.0, + "description": "Reused description for all parameters.", + "displayName": "float min/max all fields", + "max": 30.0, + "min": 20.0, + "suffix": "unit", + "type": "float", + "value": 30.0, + "variableName": "float_min_max_all_fields" + }, + { + "default": 1.8, + "description": "Reused description for all parameters.", + "displayName": "float min/max no unit", + "max": 3.0, + "min": 1.5, + "type": "float", + "value": 1.8, + "variableName": "float_min_max_no_unit" + }, + { + "default": 1.8, + "displayName": "float min/max no unit,desc", + "max": 3.0, + "min": 1.5, + "type": "float", + "value": 1.8, + "variableName": "float_min_max_no_unit_or_desc" + }, + { + "choices": [ + { + "displayName": "Low Volume (10.0µL)", + "value": 10.0 + }, + { + "displayName": "Medium Volume (20.0µL)", + "value": 20.0 + }, + { + "displayName": "High Volume (50.0µL)", + "value": 50.0 + } + ], + "default": 20.0, + "description": "Reused description for all parameters.", + "displayName": "float choices all", + "type": "float", + "value": 20.0, + "variableName": "float_choices_all_fields" + }, + { + "choices": [ + { + "displayName": "Low Volume (10.0µL)", + "value": 10.0 + }, + { + "displayName": "High Volume (50.0µL)", + "value": 50.0 + } + ], + "default": 10.0, + "description": "Reused description for all parameters.", + "displayName": "float choices no unit", + "type": "float", + "value": 10.0, + "variableName": "float_choices_no_unit" + }, + { + "choices": [ + { + "displayName": "Low Volume (10.0µL)", + "value": 10.0 + }, + { + "displayName": "Medium Volume (20.0µL)", + "value": 20.0 + }, + { + "displayName": "High Volume (50.0µL)", + "value": 50.0 + } + ], + "default": 20.0, + "displayName": "float choices no description", + "type": "float", + "value": 20.0, + "variableName": "float_choices_no_description" + }, + { + "choices": [ + { + "displayName": "Low Volume (10.0µL)", + "value": 10.0 + }, + { + "displayName": "Medium Volume (20.0µL)", + "value": 20.0 + }, + { + "displayName": "High Volume (50.0µL)", + "value": 50.0 + } + ], + "default": 20.0, + "displayName": "float choices no unit,desc", + "type": "float", + "value": 20.0, + "variableName": "float_choices_no_unit_or_desc" + }, + { + "default": false, + "description": "When on, skip aspirate and dispense steps.", + "displayName": "bool all fields", + "type": "bool", + "value": false, + "variableName": "bool_all_fields" + }, + { + "default": false, + "displayName": "bool no description", + "type": "bool", + "value": false, + "variableName": "bool_no_desc" + }, + { + "choices": [ + { + "displayName": "Single channel 50µL", + "value": "flex_1channel_50" + }, + { + "displayName": "Eight Channel 50µL", + "value": "flex_8channel_50" + } + ], + "default": "flex_1channel_50", + "description": "What pipette to use during the protocol.", + "displayName": "str choices all", + "type": "str", + "value": "flex_1channel_50", + "variableName": "str_choices_all_fields" + }, + { + "choices": [ + { + "displayName": "A", + "value": "A" + }, + { + "displayName": "B", + "value": "B" + }, + { + "displayName": "C", + "value": "C" + }, + { + "displayName": "D", + "value": "D" + }, + { + "displayName": "E", + "value": "E" + }, + { + "displayName": "F", + "value": "F" + } + ], + "default": "E", + "description": "Reused description for all parameters.", + "displayName": "str choices all many", + "type": "str", + "value": "E", + "variableName": "str_choices_all_many_fields" + }, + { + "choices": [ + { + "displayName": "Single channel 50µL", + "value": "flex_1channel_50" + }, + { + "displayName": "Eight Channel 50µL", + "value": "flex_8channel_50" + } + ], + "default": "flex_1channel_50", + "displayName": "str choices no desc", + "type": "str", + "value": "flex_1channel_50", + "variableName": "str_choices_no_desc" + } + ] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6ad5590adf][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_unit].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6ad5590adf][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_unit].json new file mode 100644 index 00000000000..5265e8ee773 --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6ad5590adf][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_unit].json @@ -0,0 +1,74 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + } + ], + "config": { + "apiVersion": [ + 2, + 18 + ], + "protocolType": "python" + }, + "errors": [ + { + "detail": "ParameterNameError [line 113]: Unit must be a string and at most 10 characters.", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ExceptionInProtocolError", + "wrappedErrors": [ + { + "detail": "opentrons.protocols.parameters.types.ParameterNameError: Unit must be a string and at most 10 characters.", + "errorCode": "4000", + "errorInfo": { + "args": "('Unit must be a string and at most 10 characters.',)", + "class": "ParameterNameError", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 80, in _parse_and_set_parameters\n exec(\"add_parameters(__param_context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_unit.py\", line 113, in add_parameters\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/_parameter_context.py\", line 56, in add_int\n parameter = parameter_definition.create_int_parameter(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 178, in create_int_parameter\n return ParameterDefinition(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 59, in __init__\n self._unit = validation.ensure_unit_string_length(unit)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/validation.py\", line 74, in ensure_unit_string_length\n raise ParameterNameError(\n" + }, + "errorType": "PythonException", + "wrappedErrors": [] + } + ] + } + ], + "files": [ + { + "name": "Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_unit.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "protocolName": "Description Too Long 2.18" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-3 Standard", + "runTimeParameters": [] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f60da4eefb][OT2_None_None_2_12_Python310SyntaxRobotAnalysisOnlyError].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6cee20a957][OT2_S_v2_12_NO_PIPETTES_Python310SyntaxRobotAnalysisOnlyError].json similarity index 96% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f60da4eefb][OT2_None_None_2_12_Python310SyntaxRobotAnalysisOnlyError].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6cee20a957][OT2_S_v2_12_NO_PIPETTES_Python310SyntaxRobotAnalysisOnlyError].json index eb21e0a61f7..695428d10ba 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f60da4eefb][OT2_None_None_2_12_Python310SyntaxRobotAnalysisOnlyError].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6cee20a957][OT2_S_v2_12_NO_PIPETTES_Python310SyntaxRobotAnalysisOnlyError].json @@ -58,7 +58,7 @@ "errors": [], "files": [ { - "name": "OT2_None_None_2_12_Python310SyntaxRobotAnalysisOnlyError.py", + "name": "OT2_S_v2_12_NO_PIPETTES_Python310SyntaxRobotAnalysisOnlyError.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[d0c057a918][Flex_P1000_96_HS_TM_MM_2_15_MagMaxRNACells96Ch].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6e34343cfc][Flex_S_v2_15_P1000_96_GRIP_HS_MB_TM_MagMaxRNAExtraction].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[d0c057a918][Flex_P1000_96_HS_TM_MM_2_15_MagMaxRNACells96Ch].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6e34343cfc][Flex_S_v2_15_P1000_96_GRIP_HS_MB_TM_MagMaxRNAExtraction].json index 325dc552421..4fedc777673 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[d0c057a918][Flex_P1000_96_HS_TM_MM_2_15_MagMaxRNACells96Ch].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6e34343cfc][Flex_S_v2_15_P1000_96_GRIP_HS_MB_TM_MagMaxRNAExtraction].json @@ -13135,7 +13135,7 @@ ], "files": [ { - "name": "Flex_P1000_96_HS_TM_MM_2_15_MagMaxRNACells96Ch.py", + "name": "Flex_S_v2_15_P1000_96_GRIP_HS_MB_TM_MagMaxRNAExtraction.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[e49dae5293][OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin1].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6e5128f107][OT2_X_v2_16_None_None_HS_HeaterShakerConflictWithTrashBin1].json similarity index 92% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[e49dae5293][OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin1].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6e5128f107][OT2_X_v2_16_None_None_HS_HeaterShakerConflictWithTrashBin1].json index 7c7138566d7..cdbe1cbc2f6 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[e49dae5293][OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin1].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6e5128f107][OT2_X_v2_16_None_None_HS_HeaterShakerConflictWithTrashBin1].json @@ -478,7 +478,7 @@ "errorInfo": { "args": "('trash bin in slot 12 prevents heaterShakerModuleV1 from using slot 11.',)", "class": "DeckConflictError", - "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin1.py\", line 11, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line 383, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/protocol_context.py\", line 814, in load_module\n module_core = self._core.load_module(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/engine/protocol.py\", line 424, in load_module\n deck_conflict.check(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/engine/deck_conflict.py\", line 203, in check\n wrapped_deck_conflict.check(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/motion_planning/deck_conflict.py\", line 223, in check\n raise DeckConflictError(\n" + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"OT2_X_v2_16_None_None_HS_HeaterShakerConflictWithTrashBin1.py\", line 11, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line 383, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/protocol_context.py\", line 814, in load_module\n module_core = self._core.load_module(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/engine/protocol.py\", line 423, in load_module\n deck_conflict.check(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/engine/deck_conflict.py\", line 203, in check\n wrapped_deck_conflict.check(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/motion_planning/deck_conflict.py\", line 223, in check\n raise DeckConflictError(\n" }, "errorType": "PythonException", "wrappedErrors": [] @@ -488,7 +488,7 @@ ], "files": [ { - "name": "OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin1.py", + "name": "OT2_X_v2_16_None_None_HS_HeaterShakerConflictWithTrashBin1.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6e744cbb48][Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultChoiceNoMatchChoice_Override_str_default_no_matching_choices].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6e744cbb48][Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultChoiceNoMatchChoice_Override_str_default_no_matching_choices].json new file mode 100644 index 00000000000..75501aa1ccd --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6e744cbb48][Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultChoiceNoMatchChoice_Override_str_default_no_matching_choices].json @@ -0,0 +1,74 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + } + ], + "config": { + "apiVersion": [ + 2, + 18 + ], + "protocolType": "python" + }, + "errors": [ + { + "detail": "ParameterValueError [line 48]: Parameter must be set to one of the allowed values of {'flex_8channel_50', 'flex_1channel_50'}.", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ExceptionInProtocolError", + "wrappedErrors": [ + { + "detail": "opentrons.protocols.parameters.types.ParameterValueError: Parameter must be set to one of the allowed values of {'flex_8channel_50', 'flex_1channel_50'}.", + "errorCode": "4000", + "errorInfo": { + "args": "(\"Parameter must be set to one of the allowed values of {'flex_8channel_50', 'flex_1channel_50'}.\",)", + "class": "ParameterValueError", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 80, in _parse_and_set_parameters\n exec(\"add_parameters(__param_context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultChoiceNoMatchChoice_Override_str_default_no_matching_choices.py\", line 48, in add_parameters\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/_parameter_context.py\", line 152, in add_str\n parameter = parameter_definition.create_str_parameter(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 241, in create_str_parameter\n return ParameterDefinition(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 84, in __init__\n self.value: ParamType = default\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 95, in value\n raise ParameterValueError(\n" + }, + "errorType": "PythonException", + "wrappedErrors": [] + } + ] + } + ], + "files": [ + { + "name": "Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultChoiceNoMatchChoice_Override_str_default_no_matching_choices.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "protocolName": "default choice does not match a choice" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-3 Standard", + "runTimeParameters": [] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[56ce1419a7][OT2_P300SLeft_MM1_MM_TM_2_3_Mix].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6f3e297a11][OT2_S_v2_3_P300S_None_MM1_MM2_TM_Mix].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[56ce1419a7][OT2_P300SLeft_MM1_MM_TM_2_3_Mix].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6f3e297a11][OT2_S_v2_3_P300S_None_MM1_MM2_TM_Mix].json index fec10bf30f7..7cb40077d2e 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[56ce1419a7][OT2_P300SLeft_MM1_MM_TM_2_3_Mix].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6f3e297a11][OT2_S_v2_3_P300S_None_MM1_MM2_TM_Mix].json @@ -3285,7 +3285,7 @@ "errors": [], "files": [ { - "name": "OT2_P300SLeft_MM1_MM_TM_2_3_Mix.py", + "name": "OT2_S_v2_3_P300S_None_MM1_MM2_TM_Mix.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[7d76f2144c][OT2_P300M_P20S_TC_HS_TM_2_16_aspirateDispenseMix0Volume].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6f84e60cb0][OT2_S_v2_16_P300M_P20S_HS_TC_TM_aspirateDispenseMix0Volume].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[7d76f2144c][OT2_P300M_P20S_TC_HS_TM_2_16_aspirateDispenseMix0Volume].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6f84e60cb0][OT2_S_v2_16_P300M_P20S_HS_TC_TM_aspirateDispenseMix0Volume].json index 526eda204d8..df4476882f5 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[7d76f2144c][OT2_P300M_P20S_TC_HS_TM_2_16_aspirateDispenseMix0Volume].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6f84e60cb0][OT2_S_v2_16_P300M_P20S_HS_TC_TM_aspirateDispenseMix0Volume].json @@ -2723,7 +2723,7 @@ "errors": [], "files": [ { - "name": "OT2_P300M_P20S_TC_HS_TM_2_16_aspirateDispenseMix0Volume.py", + "name": "OT2_S_v2_16_P300M_P20S_HS_TC_TM_aspirateDispenseMix0Volume.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[7d06568bfe][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_choice_display_name].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[7d06568bfe][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_choice_display_name].json new file mode 100644 index 00000000000..41eeee384db --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[7d06568bfe][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_choice_display_name].json @@ -0,0 +1,74 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + } + ], + "config": { + "apiVersion": [ + 2, + 18 + ], + "protocolType": "python" + }, + "errors": [ + { + "detail": "ParameterNameError [line 51]: Display name must be a string and at most 30 characters.", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ExceptionInProtocolError", + "wrappedErrors": [ + { + "detail": "opentrons.protocols.parameters.types.ParameterNameError: Display name must be a string and at most 30 characters.", + "errorCode": "4000", + "errorInfo": { + "args": "('Display name must be a string and at most 30 characters.',)", + "class": "ParameterNameError", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 80, in _parse_and_set_parameters\n exec(\"add_parameters(__param_context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_choice_display_name.py\", line 51, in add_parameters\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/_parameter_context.py\", line 152, in add_str\n parameter = parameter_definition.create_str_parameter(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 241, in create_str_parameter\n return ParameterDefinition(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 73, in __init__\n validation.validate_options(default, minimum, maximum, choices, parameter_type)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/validation.py\", line 264, in validate_options\n _validate_choices(minimum, maximum, choices, parameter_type)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/validation.py\", line 189, in _validate_choices\n ensure_display_name(display_name)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/validation.py\", line 33, in ensure_display_name\n raise ParameterNameError(\n" + }, + "errorType": "PythonException", + "wrappedErrors": [] + } + ] + } + ], + "files": [ + { + "name": "Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_choice_display_name.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "protocolName": "Description Too Long 2.18" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-3 Standard", + "runTimeParameters": [] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[7f2ef0eaff][Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultChoiceNoMatchChoice_Override_float_default_no_matching_choices].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[7f2ef0eaff][Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultChoiceNoMatchChoice_Override_float_default_no_matching_choices].json new file mode 100644 index 00000000000..8181845d3d4 --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[7f2ef0eaff][Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultChoiceNoMatchChoice_Override_float_default_no_matching_choices].json @@ -0,0 +1,74 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + } + ], + "config": { + "apiVersion": [ + 2, + 18 + ], + "protocolType": "python" + }, + "errors": [ + { + "detail": "ParameterValueError [line 36]: Parameter must be set to one of the allowed values of {160.0, 100.0, 200.0}.", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ExceptionInProtocolError", + "wrappedErrors": [ + { + "detail": "opentrons.protocols.parameters.types.ParameterValueError: Parameter must be set to one of the allowed values of {160.0, 100.0, 200.0}.", + "errorCode": "4000", + "errorInfo": { + "args": "('Parameter must be set to one of the allowed values of {160.0, 100.0, 200.0}.',)", + "class": "ParameterValueError", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 80, in _parse_and_set_parameters\n exec(\"add_parameters(__param_context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultChoiceNoMatchChoice_Override_float_default_no_matching_choices.py\", line 36, in add_parameters\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/_parameter_context.py\", line 93, in add_float\n parameter = parameter_definition.create_float_parameter(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 202, in create_float_parameter\n return ParameterDefinition(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 84, in __init__\n self.value: ParamType = default\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 95, in value\n raise ParameterValueError(\n" + }, + "errorType": "PythonException", + "wrappedErrors": [] + } + ] + } + ], + "files": [ + { + "name": "Flex_X_v2_18_NO_PIPETTES_Overrides_DefaultChoiceNoMatchChoice_Override_float_default_no_matching_choices.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "protocolName": "default choice does not match a choice" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-3 Standard", + "runTimeParameters": [] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[7be98bf838][Flex_None_None_2_16_AnalysisError_TrashBinInCol2].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[82e9853b34][Flex_X_v2_16_NO_PIPETTES_TrashBinInCol2].json similarity index 72% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[7be98bf838][Flex_None_None_2_16_AnalysisError_TrashBinInCol2].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[82e9853b34][Flex_X_v2_16_NO_PIPETTES_TrashBinInCol2].json index bd95551628d..80b5f0999af 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[7be98bf838][Flex_None_None_2_16_AnalysisError_TrashBinInCol2].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[82e9853b34][Flex_X_v2_16_NO_PIPETTES_TrashBinInCol2].json @@ -28,7 +28,7 @@ "errorInfo": { "args": "('Invalid location for trash bin: C2.\\nValid slots: Any slot in column 1 or 3.',)", "class": "InvalidTrashBinLocationError", - "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_None_None_2_16_AnalysisError_TrashBinInCol2.py\", line 15, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line 383, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/protocol_context.py\", line 513, in load_trash_bin\n addressable_area_name = validation.ensure_and_convert_trash_bin_location(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/validation.py\", line 327, in ensure_and_convert_trash_bin_location\n raise InvalidTrashBinLocationError(\n" + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_X_v2_16_NO_PIPETTES_TrashBinInCol2.py\", line 15, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line 383, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/protocol_context.py\", line 513, in load_trash_bin\n addressable_area_name = validation.ensure_and_convert_trash_bin_location(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/validation.py\", line 331, in ensure_and_convert_trash_bin_location\n raise InvalidTrashBinLocationError(\n" }, "errorType": "PythonException", "wrappedErrors": [] @@ -38,7 +38,7 @@ ], "files": [ { - "name": "Flex_None_None_2_16_AnalysisError_TrashBinInCol2.py", + "name": "Flex_X_v2_16_NO_PIPETTES_TrashBinInCol2.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[2251879791][OT2_P300M_P20S_None_2_12_FailOnRun].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[8455adcea9][OT2_S_v2_12_P300M_P20S_FailOnRun].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[2251879791][OT2_P300M_P20S_None_2_12_FailOnRun].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[8455adcea9][OT2_S_v2_12_P300M_P20S_FailOnRun].json index 5608b51bab4..b44fa048895 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[2251879791][OT2_P300M_P20S_None_2_12_FailOnRun].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[8455adcea9][OT2_S_v2_12_P300M_P20S_FailOnRun].json @@ -2583,7 +2583,7 @@ "errors": [], "files": [ { - "name": "OT2_P300M_P20S_None_2_12_FailOnRun.py", + "name": "OT2_S_v2_12_P300M_P20S_FailOnRun.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4017e085e6][OT2_P300M_P20S_TC_HS_TM_2_14_SmokeTestV3].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[8860ee702c][OT2_S_v2_14_P300M_P20S_HS_TC_TM_SmokeTestV3].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4017e085e6][OT2_P300M_P20S_TC_HS_TM_2_14_SmokeTestV3].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[8860ee702c][OT2_S_v2_14_P300M_P20S_HS_TC_TM_SmokeTestV3].json index cca27aadcbb..47aea45189a 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4017e085e6][OT2_P300M_P20S_TC_HS_TM_2_14_SmokeTestV3].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[8860ee702c][OT2_S_v2_14_P300M_P20S_HS_TC_TM_SmokeTestV3].json @@ -12728,7 +12728,7 @@ "errors": [], "files": [ { - "name": "OT2_P300M_P20S_TC_HS_TM_2_14_SmokeTestV3.py", + "name": "OT2_S_v2_14_P300M_P20S_HS_TC_TM_SmokeTestV3.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[8f2cb4b133][Flex_P50MLeft_P1000MRight_None_2_15_ABRKAPALibraryQuantLongv2].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[88a20da279][Flex_S_v2_15_P50M_P1000M_KAPALibraryQuantLongv2].json similarity index 96% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[8f2cb4b133][Flex_P50MLeft_P1000MRight_None_2_15_ABRKAPALibraryQuantLongv2].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[88a20da279][Flex_S_v2_15_P50M_P1000M_KAPALibraryQuantLongv2].json index 021cb9bf4db..24f2c1e2fb6 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[8f2cb4b133][Flex_P50MLeft_P1000MRight_None_2_15_ABRKAPALibraryQuantLongv2].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[88a20da279][Flex_S_v2_15_P50M_P1000M_KAPALibraryQuantLongv2].json @@ -17877,7 +17877,7 @@ "commandType": "custom", "notes": [], "params": { - "legacyCommandText": "Flex_P50MLeft_P1000MRight_None_2_15_ABRKAPALibraryQuantLongv2.py", + "legacyCommandText": "Flex_S_v2_15_P50M_P1000M_KAPALibraryQuantLongv2.py", "legacyCommandType": "command.COMMENT" }, "result": {}, @@ -17977,7 +17977,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18003,7 +18003,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18029,7 +18029,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18055,7 +18055,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18081,7 +18081,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18107,7 +18107,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18166,7 +18166,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18192,7 +18192,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 98.0, "wellLocation": { "offset": { @@ -18251,7 +18251,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 95.0, "wellLocation": { "offset": { @@ -18334,7 +18334,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -18382,7 +18382,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18408,7 +18408,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18434,7 +18434,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18460,7 +18460,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18486,7 +18486,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18512,7 +18512,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18571,7 +18571,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18597,7 +18597,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 98.0, "wellLocation": { "offset": { @@ -18656,7 +18656,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 95.0, "wellLocation": { "offset": { @@ -18739,7 +18739,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -18787,7 +18787,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18813,7 +18813,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18839,7 +18839,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18865,7 +18865,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18891,7 +18891,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18917,7 +18917,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18976,7 +18976,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 200.0, "wellLocation": { "offset": { @@ -19002,7 +19002,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 98.0, "wellLocation": { "offset": { @@ -19061,7 +19061,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 95.0, "wellLocation": { "offset": { @@ -19144,7 +19144,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -19248,7 +19248,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 2.0, "wellLocation": { "offset": { @@ -19274,7 +19274,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 2.0, "wellLocation": { "offset": { @@ -19350,7 +19350,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 2.0, "wellLocation": { "offset": { @@ -19376,7 +19376,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 2.0, "wellLocation": { "offset": { @@ -19452,7 +19452,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 2.0, "wellLocation": { "offset": { @@ -19478,7 +19478,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 2.0, "wellLocation": { "offset": { @@ -19588,7 +19588,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -19614,7 +19614,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -19640,7 +19640,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -19666,7 +19666,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -19692,7 +19692,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -19718,7 +19718,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -19744,7 +19744,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -19770,7 +19770,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -19796,7 +19796,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -19822,7 +19822,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -19848,7 +19848,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -19874,7 +19874,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -19900,7 +19900,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -19926,7 +19926,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -19952,7 +19952,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -19978,7 +19978,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20004,7 +20004,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20030,7 +20030,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20056,7 +20056,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20082,7 +20082,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20108,7 +20108,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20134,7 +20134,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20160,7 +20160,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20186,7 +20186,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20212,7 +20212,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20238,7 +20238,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20264,7 +20264,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20290,7 +20290,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20316,7 +20316,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20342,7 +20342,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20368,7 +20368,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20394,7 +20394,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20420,7 +20420,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20446,7 +20446,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20472,7 +20472,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20498,7 +20498,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20524,7 +20524,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20550,7 +20550,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20576,7 +20576,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20602,7 +20602,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20628,7 +20628,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20654,7 +20654,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20680,7 +20680,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20706,7 +20706,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20732,7 +20732,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20758,7 +20758,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20784,7 +20784,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20810,7 +20810,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20836,7 +20836,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20862,7 +20862,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20888,7 +20888,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20914,7 +20914,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20940,7 +20940,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20966,7 +20966,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -20992,7 +20992,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21018,7 +21018,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21044,7 +21044,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21070,7 +21070,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21096,7 +21096,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21122,7 +21122,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21148,7 +21148,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21174,7 +21174,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21200,7 +21200,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21226,7 +21226,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21252,7 +21252,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21278,7 +21278,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21304,7 +21304,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21330,7 +21330,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21356,7 +21356,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21382,7 +21382,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21408,7 +21408,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21434,7 +21434,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21460,7 +21460,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21486,7 +21486,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21512,7 +21512,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21538,7 +21538,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21564,7 +21564,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21590,7 +21590,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21616,7 +21616,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21642,7 +21642,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21668,7 +21668,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21694,7 +21694,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21720,7 +21720,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21746,7 +21746,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21772,7 +21772,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21798,7 +21798,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21824,7 +21824,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21850,7 +21850,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21876,7 +21876,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21902,7 +21902,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21928,7 +21928,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21954,7 +21954,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21980,7 +21980,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22006,7 +22006,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22032,7 +22032,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22058,7 +22058,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22084,7 +22084,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22110,7 +22110,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22136,7 +22136,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22162,7 +22162,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22295,7 +22295,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22321,7 +22321,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22347,7 +22347,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22373,7 +22373,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22399,7 +22399,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22425,7 +22425,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22451,7 +22451,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22477,7 +22477,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22503,7 +22503,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22529,7 +22529,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22555,7 +22555,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22581,7 +22581,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22607,7 +22607,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22633,7 +22633,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22659,7 +22659,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22685,7 +22685,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22711,7 +22711,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22737,7 +22737,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22763,7 +22763,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22789,7 +22789,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22815,7 +22815,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22841,7 +22841,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22867,7 +22867,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22893,7 +22893,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22919,7 +22919,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22945,7 +22945,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22971,7 +22971,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -22997,7 +22997,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23023,7 +23023,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23049,7 +23049,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23075,7 +23075,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23101,7 +23101,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23127,7 +23127,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23153,7 +23153,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23179,7 +23179,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23205,7 +23205,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23231,7 +23231,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23257,7 +23257,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23283,7 +23283,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23309,7 +23309,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23335,7 +23335,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23361,7 +23361,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23387,7 +23387,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23413,7 +23413,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23439,7 +23439,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23465,7 +23465,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23491,7 +23491,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23517,7 +23517,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23543,7 +23543,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23569,7 +23569,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23595,7 +23595,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23621,7 +23621,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23647,7 +23647,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23673,7 +23673,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23699,7 +23699,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23725,7 +23725,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23751,7 +23751,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23777,7 +23777,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23803,7 +23803,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23829,7 +23829,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23855,7 +23855,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23881,7 +23881,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23907,7 +23907,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23933,7 +23933,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23959,7 +23959,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -23985,7 +23985,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24011,7 +24011,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24037,7 +24037,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24063,7 +24063,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24089,7 +24089,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24115,7 +24115,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24141,7 +24141,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24167,7 +24167,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24193,7 +24193,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24219,7 +24219,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24245,7 +24245,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24271,7 +24271,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24297,7 +24297,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24323,7 +24323,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24349,7 +24349,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24375,7 +24375,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24401,7 +24401,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24427,7 +24427,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24453,7 +24453,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24479,7 +24479,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24505,7 +24505,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24531,7 +24531,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24557,7 +24557,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24583,7 +24583,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24609,7 +24609,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24635,7 +24635,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24661,7 +24661,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24687,7 +24687,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24713,7 +24713,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24739,7 +24739,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24765,7 +24765,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24791,7 +24791,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24817,7 +24817,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24843,7 +24843,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -24869,7 +24869,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25002,7 +25002,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25028,7 +25028,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25054,7 +25054,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25080,7 +25080,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25106,7 +25106,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25132,7 +25132,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25158,7 +25158,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25184,7 +25184,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25210,7 +25210,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25236,7 +25236,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25262,7 +25262,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25288,7 +25288,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25314,7 +25314,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25340,7 +25340,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25366,7 +25366,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25392,7 +25392,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25418,7 +25418,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25444,7 +25444,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25470,7 +25470,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25496,7 +25496,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25522,7 +25522,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25548,7 +25548,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25574,7 +25574,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25600,7 +25600,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25626,7 +25626,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25652,7 +25652,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25678,7 +25678,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25704,7 +25704,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25730,7 +25730,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25756,7 +25756,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25782,7 +25782,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25808,7 +25808,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25834,7 +25834,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25860,7 +25860,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25886,7 +25886,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25912,7 +25912,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25938,7 +25938,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25964,7 +25964,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25990,7 +25990,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26016,7 +26016,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26042,7 +26042,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26068,7 +26068,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26094,7 +26094,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26120,7 +26120,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26146,7 +26146,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26172,7 +26172,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26198,7 +26198,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26224,7 +26224,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26250,7 +26250,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26276,7 +26276,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26302,7 +26302,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26328,7 +26328,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26354,7 +26354,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26380,7 +26380,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26406,7 +26406,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26432,7 +26432,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26458,7 +26458,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26484,7 +26484,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26510,7 +26510,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26536,7 +26536,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26562,7 +26562,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26588,7 +26588,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26614,7 +26614,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26640,7 +26640,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26666,7 +26666,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26692,7 +26692,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26718,7 +26718,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26744,7 +26744,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26770,7 +26770,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26796,7 +26796,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26822,7 +26822,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26848,7 +26848,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26874,7 +26874,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26900,7 +26900,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26926,7 +26926,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26952,7 +26952,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -26978,7 +26978,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27004,7 +27004,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27030,7 +27030,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27056,7 +27056,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27082,7 +27082,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27108,7 +27108,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27134,7 +27134,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27160,7 +27160,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27186,7 +27186,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27212,7 +27212,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27238,7 +27238,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27264,7 +27264,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27290,7 +27290,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27316,7 +27316,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27342,7 +27342,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27368,7 +27368,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27394,7 +27394,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27420,7 +27420,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27446,7 +27446,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27472,7 +27472,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27498,7 +27498,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27524,7 +27524,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27550,7 +27550,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27576,7 +27576,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27715,7 +27715,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 5.0, "wellLocation": { "offset": { @@ -27741,7 +27741,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 5.0, "wellLocation": { "offset": { @@ -27817,7 +27817,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 5.0, "wellLocation": { "offset": { @@ -27843,7 +27843,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 5.0, "wellLocation": { "offset": { @@ -27919,7 +27919,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 5.0, "wellLocation": { "offset": { @@ -27945,7 +27945,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 5.0, "wellLocation": { "offset": { @@ -28055,7 +28055,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28081,7 +28081,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28107,7 +28107,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28133,7 +28133,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28159,7 +28159,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28185,7 +28185,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28211,7 +28211,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28237,7 +28237,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28263,7 +28263,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28289,7 +28289,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28315,7 +28315,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28341,7 +28341,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28367,7 +28367,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28393,7 +28393,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28419,7 +28419,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28445,7 +28445,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28471,7 +28471,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28497,7 +28497,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28523,7 +28523,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28549,7 +28549,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28575,7 +28575,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28601,7 +28601,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28627,7 +28627,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28653,7 +28653,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28679,7 +28679,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28705,7 +28705,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28731,7 +28731,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28757,7 +28757,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28783,7 +28783,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28809,7 +28809,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28835,7 +28835,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28861,7 +28861,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28887,7 +28887,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28913,7 +28913,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28939,7 +28939,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28965,7 +28965,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28991,7 +28991,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29017,7 +29017,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29043,7 +29043,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29069,7 +29069,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29095,7 +29095,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29121,7 +29121,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29147,7 +29147,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29173,7 +29173,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29199,7 +29199,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29225,7 +29225,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29251,7 +29251,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29277,7 +29277,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29303,7 +29303,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29329,7 +29329,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29355,7 +29355,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29381,7 +29381,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29407,7 +29407,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29433,7 +29433,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29459,7 +29459,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29485,7 +29485,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29511,7 +29511,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29537,7 +29537,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29563,7 +29563,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29589,7 +29589,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29615,7 +29615,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29641,7 +29641,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29667,7 +29667,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29693,7 +29693,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29719,7 +29719,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29745,7 +29745,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29771,7 +29771,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29797,7 +29797,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29823,7 +29823,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29849,7 +29849,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29875,7 +29875,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29901,7 +29901,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29927,7 +29927,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29953,7 +29953,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -29979,7 +29979,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30005,7 +30005,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30031,7 +30031,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30057,7 +30057,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30083,7 +30083,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30109,7 +30109,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30135,7 +30135,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30161,7 +30161,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30187,7 +30187,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30213,7 +30213,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30239,7 +30239,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30265,7 +30265,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30291,7 +30291,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30317,7 +30317,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30343,7 +30343,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30369,7 +30369,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30395,7 +30395,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30421,7 +30421,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30447,7 +30447,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30473,7 +30473,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30499,7 +30499,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30525,7 +30525,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30551,7 +30551,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30577,7 +30577,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30603,7 +30603,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30629,7 +30629,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30762,7 +30762,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30788,7 +30788,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30814,7 +30814,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30840,7 +30840,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30866,7 +30866,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30892,7 +30892,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30918,7 +30918,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30944,7 +30944,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30970,7 +30970,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -30996,7 +30996,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31022,7 +31022,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31048,7 +31048,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31074,7 +31074,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31100,7 +31100,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31126,7 +31126,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31152,7 +31152,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31178,7 +31178,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31204,7 +31204,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31230,7 +31230,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31256,7 +31256,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31282,7 +31282,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31308,7 +31308,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31334,7 +31334,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31360,7 +31360,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31386,7 +31386,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31412,7 +31412,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31438,7 +31438,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31464,7 +31464,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31490,7 +31490,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31516,7 +31516,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31542,7 +31542,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31568,7 +31568,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31594,7 +31594,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31620,7 +31620,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31646,7 +31646,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31672,7 +31672,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31698,7 +31698,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31724,7 +31724,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31750,7 +31750,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31776,7 +31776,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31802,7 +31802,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31828,7 +31828,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31854,7 +31854,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31880,7 +31880,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31906,7 +31906,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31932,7 +31932,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31958,7 +31958,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31984,7 +31984,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32010,7 +32010,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32036,7 +32036,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32062,7 +32062,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32088,7 +32088,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32114,7 +32114,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32140,7 +32140,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32166,7 +32166,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32192,7 +32192,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32218,7 +32218,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32244,7 +32244,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32270,7 +32270,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32296,7 +32296,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32322,7 +32322,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32348,7 +32348,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32374,7 +32374,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32400,7 +32400,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32426,7 +32426,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32452,7 +32452,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32478,7 +32478,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32504,7 +32504,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32530,7 +32530,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32556,7 +32556,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32582,7 +32582,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32608,7 +32608,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32634,7 +32634,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32660,7 +32660,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32686,7 +32686,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32712,7 +32712,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32738,7 +32738,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32764,7 +32764,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32790,7 +32790,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32816,7 +32816,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32842,7 +32842,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32868,7 +32868,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32894,7 +32894,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32920,7 +32920,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32946,7 +32946,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32972,7 +32972,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -32998,7 +32998,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33024,7 +33024,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33050,7 +33050,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33076,7 +33076,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33102,7 +33102,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33128,7 +33128,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33154,7 +33154,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33180,7 +33180,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33206,7 +33206,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33232,7 +33232,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33258,7 +33258,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33284,7 +33284,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33310,7 +33310,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33336,7 +33336,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33469,7 +33469,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33495,7 +33495,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33521,7 +33521,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33547,7 +33547,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33573,7 +33573,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33599,7 +33599,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33625,7 +33625,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33651,7 +33651,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33677,7 +33677,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33703,7 +33703,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33729,7 +33729,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33755,7 +33755,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33781,7 +33781,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33807,7 +33807,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33833,7 +33833,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33859,7 +33859,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33885,7 +33885,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33911,7 +33911,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33937,7 +33937,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33963,7 +33963,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33989,7 +33989,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34015,7 +34015,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34041,7 +34041,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34067,7 +34067,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34093,7 +34093,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34119,7 +34119,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34145,7 +34145,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34171,7 +34171,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34197,7 +34197,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34223,7 +34223,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34249,7 +34249,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34275,7 +34275,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34301,7 +34301,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34327,7 +34327,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34353,7 +34353,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34379,7 +34379,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34405,7 +34405,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34431,7 +34431,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34457,7 +34457,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34483,7 +34483,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34509,7 +34509,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34535,7 +34535,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34561,7 +34561,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34587,7 +34587,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34613,7 +34613,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34639,7 +34639,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34665,7 +34665,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34691,7 +34691,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34717,7 +34717,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34743,7 +34743,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34769,7 +34769,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34795,7 +34795,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34821,7 +34821,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34847,7 +34847,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34873,7 +34873,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34899,7 +34899,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34925,7 +34925,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34951,7 +34951,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -34977,7 +34977,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35003,7 +35003,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35029,7 +35029,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35055,7 +35055,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35081,7 +35081,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35107,7 +35107,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35133,7 +35133,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35159,7 +35159,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35185,7 +35185,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35211,7 +35211,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35237,7 +35237,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35263,7 +35263,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35289,7 +35289,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35315,7 +35315,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35341,7 +35341,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35367,7 +35367,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35393,7 +35393,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35419,7 +35419,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35445,7 +35445,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35471,7 +35471,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35497,7 +35497,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35523,7 +35523,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35549,7 +35549,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35575,7 +35575,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35601,7 +35601,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35627,7 +35627,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35653,7 +35653,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35679,7 +35679,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35705,7 +35705,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35731,7 +35731,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35757,7 +35757,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35783,7 +35783,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35809,7 +35809,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35835,7 +35835,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35861,7 +35861,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35887,7 +35887,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35913,7 +35913,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35939,7 +35939,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35965,7 +35965,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35991,7 +35991,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -36017,7 +36017,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -36043,7 +36043,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -36182,7 +36182,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -36208,7 +36208,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -36234,7 +36234,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -36260,7 +36260,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -36286,7 +36286,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -36312,7 +36312,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -36338,7 +36338,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -36364,7 +36364,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -36440,7 +36440,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -36466,7 +36466,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -36492,7 +36492,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -36518,7 +36518,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -36544,7 +36544,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -36570,7 +36570,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -36596,7 +36596,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -36622,7 +36622,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -36728,7 +36728,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -36754,7 +36754,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -36863,7 +36863,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -36889,7 +36889,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -37028,7 +37028,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -37054,7 +37054,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -37163,7 +37163,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -37189,7 +37189,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -37298,7 +37298,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -37324,7 +37324,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -37433,7 +37433,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -37459,7 +37459,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -37568,7 +37568,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -37594,7 +37594,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -37703,7 +37703,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -37729,7 +37729,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -37892,7 +37892,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -37918,7 +37918,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -37944,7 +37944,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -37970,7 +37970,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -37996,7 +37996,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38022,7 +38022,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38048,7 +38048,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38074,7 +38074,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38100,7 +38100,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38126,7 +38126,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38152,7 +38152,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38178,7 +38178,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38204,7 +38204,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38230,7 +38230,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38256,7 +38256,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38282,7 +38282,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38308,7 +38308,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38334,7 +38334,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38360,7 +38360,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38386,7 +38386,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38412,7 +38412,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38438,7 +38438,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38464,7 +38464,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38490,7 +38490,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38516,7 +38516,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38542,7 +38542,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38568,7 +38568,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38594,7 +38594,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38620,7 +38620,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38646,7 +38646,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38672,7 +38672,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38698,7 +38698,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38724,7 +38724,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38750,7 +38750,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38776,7 +38776,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38802,7 +38802,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38828,7 +38828,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38854,7 +38854,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38880,7 +38880,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38906,7 +38906,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38932,7 +38932,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38958,7 +38958,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38984,7 +38984,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -39010,7 +39010,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -39036,7 +39036,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -39062,7 +39062,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -39088,7 +39088,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -39114,7 +39114,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -39140,7 +39140,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -39166,7 +39166,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -39192,7 +39192,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -39218,7 +39218,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -39244,7 +39244,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -39270,7 +39270,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -39296,7 +39296,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -39322,7 +39322,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -39348,7 +39348,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -39374,7 +39374,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -39400,7 +39400,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -39426,7 +39426,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -39452,7 +39452,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -39520,7 +39520,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -39588,7 +39588,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -39656,7 +39656,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -39724,7 +39724,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -39792,7 +39792,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -39860,7 +39860,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -39969,7 +39969,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -39995,7 +39995,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40021,7 +40021,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40047,7 +40047,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40073,7 +40073,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40099,7 +40099,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40125,7 +40125,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40151,7 +40151,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40177,7 +40177,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40203,7 +40203,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40229,7 +40229,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40255,7 +40255,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40281,7 +40281,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40307,7 +40307,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40333,7 +40333,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40359,7 +40359,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40385,7 +40385,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40411,7 +40411,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40437,7 +40437,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40463,7 +40463,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40489,7 +40489,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40515,7 +40515,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40541,7 +40541,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40567,7 +40567,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40593,7 +40593,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40619,7 +40619,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40645,7 +40645,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40671,7 +40671,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40697,7 +40697,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40723,7 +40723,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40749,7 +40749,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40775,7 +40775,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40801,7 +40801,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40827,7 +40827,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40853,7 +40853,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40879,7 +40879,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40905,7 +40905,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40931,7 +40931,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40957,7 +40957,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40983,7 +40983,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41009,7 +41009,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41035,7 +41035,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41061,7 +41061,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41087,7 +41087,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41113,7 +41113,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41139,7 +41139,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41165,7 +41165,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41191,7 +41191,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41217,7 +41217,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41243,7 +41243,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41269,7 +41269,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41295,7 +41295,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41321,7 +41321,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41347,7 +41347,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41373,7 +41373,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41399,7 +41399,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41425,7 +41425,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41451,7 +41451,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41477,7 +41477,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41503,7 +41503,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41529,7 +41529,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -41597,7 +41597,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -41665,7 +41665,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -41733,7 +41733,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -41801,7 +41801,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -41869,7 +41869,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -41937,7 +41937,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -42046,7 +42046,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42072,7 +42072,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42098,7 +42098,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42124,7 +42124,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42150,7 +42150,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42176,7 +42176,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42202,7 +42202,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42228,7 +42228,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42254,7 +42254,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42280,7 +42280,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42306,7 +42306,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42332,7 +42332,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42358,7 +42358,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42384,7 +42384,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42410,7 +42410,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42436,7 +42436,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42462,7 +42462,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42488,7 +42488,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42514,7 +42514,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42540,7 +42540,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42566,7 +42566,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42592,7 +42592,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42618,7 +42618,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42644,7 +42644,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42670,7 +42670,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42696,7 +42696,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42722,7 +42722,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42748,7 +42748,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42774,7 +42774,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42800,7 +42800,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42826,7 +42826,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42852,7 +42852,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42878,7 +42878,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42904,7 +42904,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42930,7 +42930,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42956,7 +42956,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -42982,7 +42982,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43008,7 +43008,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43034,7 +43034,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43060,7 +43060,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43086,7 +43086,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43112,7 +43112,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43138,7 +43138,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43164,7 +43164,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43190,7 +43190,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43216,7 +43216,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43242,7 +43242,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43268,7 +43268,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43294,7 +43294,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43320,7 +43320,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43346,7 +43346,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43372,7 +43372,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43398,7 +43398,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43424,7 +43424,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43450,7 +43450,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43476,7 +43476,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43502,7 +43502,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43528,7 +43528,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43554,7 +43554,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43580,7 +43580,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43606,7 +43606,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -43674,7 +43674,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -43742,7 +43742,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -43810,7 +43810,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -43878,7 +43878,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -43946,7 +43946,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -44014,7 +44014,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -44123,7 +44123,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44149,7 +44149,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44175,7 +44175,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44201,7 +44201,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44227,7 +44227,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44253,7 +44253,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44279,7 +44279,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44305,7 +44305,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44331,7 +44331,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44357,7 +44357,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44383,7 +44383,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44409,7 +44409,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44435,7 +44435,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44461,7 +44461,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44487,7 +44487,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44513,7 +44513,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44539,7 +44539,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44565,7 +44565,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44591,7 +44591,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44617,7 +44617,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44643,7 +44643,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44669,7 +44669,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44695,7 +44695,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44721,7 +44721,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44747,7 +44747,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44773,7 +44773,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44799,7 +44799,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44825,7 +44825,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44851,7 +44851,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44877,7 +44877,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44903,7 +44903,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44929,7 +44929,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44955,7 +44955,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44981,7 +44981,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45007,7 +45007,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45033,7 +45033,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45059,7 +45059,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45085,7 +45085,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45111,7 +45111,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45137,7 +45137,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45163,7 +45163,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45189,7 +45189,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45215,7 +45215,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45241,7 +45241,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45267,7 +45267,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45293,7 +45293,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45319,7 +45319,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45345,7 +45345,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45371,7 +45371,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45397,7 +45397,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45423,7 +45423,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45449,7 +45449,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45475,7 +45475,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45501,7 +45501,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45527,7 +45527,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45553,7 +45553,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45579,7 +45579,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45605,7 +45605,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45631,7 +45631,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45657,7 +45657,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45683,7 +45683,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -45751,7 +45751,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -45819,7 +45819,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -45887,7 +45887,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -45955,7 +45955,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -46023,7 +46023,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -46091,7 +46091,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -46200,7 +46200,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46226,7 +46226,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46252,7 +46252,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46278,7 +46278,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46304,7 +46304,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46330,7 +46330,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46356,7 +46356,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46382,7 +46382,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46408,7 +46408,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46434,7 +46434,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46460,7 +46460,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46486,7 +46486,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46512,7 +46512,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46538,7 +46538,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46564,7 +46564,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46590,7 +46590,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46616,7 +46616,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46642,7 +46642,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46668,7 +46668,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46694,7 +46694,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46720,7 +46720,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46746,7 +46746,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46772,7 +46772,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46798,7 +46798,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46824,7 +46824,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46850,7 +46850,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46876,7 +46876,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46902,7 +46902,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46928,7 +46928,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46954,7 +46954,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46980,7 +46980,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47006,7 +47006,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47032,7 +47032,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47058,7 +47058,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47084,7 +47084,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47110,7 +47110,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47136,7 +47136,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47162,7 +47162,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47188,7 +47188,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47214,7 +47214,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47240,7 +47240,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47266,7 +47266,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47292,7 +47292,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47318,7 +47318,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47344,7 +47344,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47370,7 +47370,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47396,7 +47396,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47422,7 +47422,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47448,7 +47448,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47474,7 +47474,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47500,7 +47500,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47526,7 +47526,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47552,7 +47552,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47578,7 +47578,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47604,7 +47604,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47630,7 +47630,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47656,7 +47656,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47682,7 +47682,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47708,7 +47708,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47734,7 +47734,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47760,7 +47760,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -47828,7 +47828,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -47896,7 +47896,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -47964,7 +47964,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -48032,7 +48032,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -48100,7 +48100,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -48168,7 +48168,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -48277,7 +48277,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48303,7 +48303,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48329,7 +48329,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48355,7 +48355,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48381,7 +48381,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48407,7 +48407,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48433,7 +48433,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48459,7 +48459,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48485,7 +48485,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48511,7 +48511,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48537,7 +48537,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48563,7 +48563,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48589,7 +48589,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48615,7 +48615,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48641,7 +48641,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48667,7 +48667,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48693,7 +48693,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48719,7 +48719,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48745,7 +48745,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48771,7 +48771,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48797,7 +48797,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48823,7 +48823,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48849,7 +48849,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48875,7 +48875,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48901,7 +48901,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48927,7 +48927,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48953,7 +48953,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -48979,7 +48979,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49005,7 +49005,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49031,7 +49031,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49057,7 +49057,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49083,7 +49083,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49109,7 +49109,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49135,7 +49135,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49161,7 +49161,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49187,7 +49187,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49213,7 +49213,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49239,7 +49239,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49265,7 +49265,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49291,7 +49291,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49317,7 +49317,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49343,7 +49343,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49369,7 +49369,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49395,7 +49395,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49421,7 +49421,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49447,7 +49447,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49473,7 +49473,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49499,7 +49499,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49525,7 +49525,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49551,7 +49551,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49577,7 +49577,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49603,7 +49603,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49629,7 +49629,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49655,7 +49655,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49681,7 +49681,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49707,7 +49707,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49733,7 +49733,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49759,7 +49759,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49785,7 +49785,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49811,7 +49811,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -49837,7 +49837,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -49905,7 +49905,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -49973,7 +49973,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -50041,7 +50041,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -50109,7 +50109,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -50177,7 +50177,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -50245,7 +50245,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -50354,7 +50354,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50380,7 +50380,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50406,7 +50406,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50432,7 +50432,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50458,7 +50458,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50484,7 +50484,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50510,7 +50510,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50536,7 +50536,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50562,7 +50562,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50588,7 +50588,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50614,7 +50614,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50640,7 +50640,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50666,7 +50666,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50692,7 +50692,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50718,7 +50718,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50744,7 +50744,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50770,7 +50770,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50796,7 +50796,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50822,7 +50822,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50848,7 +50848,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50874,7 +50874,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50900,7 +50900,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50926,7 +50926,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50952,7 +50952,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -50978,7 +50978,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51004,7 +51004,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51030,7 +51030,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51056,7 +51056,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51082,7 +51082,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51108,7 +51108,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51134,7 +51134,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51160,7 +51160,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51186,7 +51186,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51212,7 +51212,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51238,7 +51238,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51264,7 +51264,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51290,7 +51290,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51316,7 +51316,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51342,7 +51342,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51368,7 +51368,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51394,7 +51394,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51420,7 +51420,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51446,7 +51446,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51472,7 +51472,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51498,7 +51498,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51524,7 +51524,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51550,7 +51550,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51576,7 +51576,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51602,7 +51602,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51628,7 +51628,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51654,7 +51654,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51680,7 +51680,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51706,7 +51706,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51732,7 +51732,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51758,7 +51758,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51784,7 +51784,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51810,7 +51810,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51836,7 +51836,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51862,7 +51862,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51888,7 +51888,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51914,7 +51914,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -51982,7 +51982,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -52050,7 +52050,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -52118,7 +52118,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -52186,7 +52186,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -52254,7 +52254,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -52322,7 +52322,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -52431,7 +52431,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -52457,7 +52457,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -52483,7 +52483,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -52509,7 +52509,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -52535,7 +52535,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -52561,7 +52561,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -52587,7 +52587,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -52613,7 +52613,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -52639,7 +52639,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -52665,7 +52665,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -52691,7 +52691,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -52717,7 +52717,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -52743,7 +52743,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -52769,7 +52769,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -52795,7 +52795,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -52821,7 +52821,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -52847,7 +52847,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -52873,7 +52873,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -52899,7 +52899,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -52925,7 +52925,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -52951,7 +52951,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -52977,7 +52977,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53003,7 +53003,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53029,7 +53029,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53055,7 +53055,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53081,7 +53081,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53107,7 +53107,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53133,7 +53133,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53159,7 +53159,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53185,7 +53185,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53211,7 +53211,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53237,7 +53237,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53263,7 +53263,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53289,7 +53289,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53315,7 +53315,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53341,7 +53341,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53367,7 +53367,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53393,7 +53393,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53419,7 +53419,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53445,7 +53445,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53471,7 +53471,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53497,7 +53497,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53523,7 +53523,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53549,7 +53549,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53575,7 +53575,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53601,7 +53601,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53627,7 +53627,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53653,7 +53653,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53679,7 +53679,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53705,7 +53705,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53731,7 +53731,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53757,7 +53757,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53783,7 +53783,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53809,7 +53809,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53835,7 +53835,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53861,7 +53861,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53887,7 +53887,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53913,7 +53913,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53939,7 +53939,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53965,7 +53965,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53991,7 +53991,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -54059,7 +54059,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -54127,7 +54127,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -54195,7 +54195,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -54263,7 +54263,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -54331,7 +54331,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -54399,7 +54399,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -54514,7 +54514,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -54540,7 +54540,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -54566,7 +54566,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -54592,7 +54592,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -54618,7 +54618,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -54644,7 +54644,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -54670,7 +54670,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -54696,7 +54696,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -54772,7 +54772,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -54798,7 +54798,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -54824,7 +54824,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -54850,7 +54850,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -54876,7 +54876,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -54902,7 +54902,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -54928,7 +54928,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -54954,7 +54954,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -55060,7 +55060,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -55086,7 +55086,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -55195,7 +55195,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -55221,7 +55221,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -55360,7 +55360,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -55386,7 +55386,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -55495,7 +55495,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -55521,7 +55521,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -55630,7 +55630,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -55656,7 +55656,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -55765,7 +55765,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -55791,7 +55791,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -55900,7 +55900,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -55926,7 +55926,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -56035,7 +56035,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -56061,7 +56061,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -56224,7 +56224,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56250,7 +56250,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56276,7 +56276,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56302,7 +56302,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56328,7 +56328,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56354,7 +56354,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56380,7 +56380,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56406,7 +56406,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56432,7 +56432,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56458,7 +56458,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56484,7 +56484,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56510,7 +56510,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56536,7 +56536,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56562,7 +56562,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56588,7 +56588,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56614,7 +56614,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56640,7 +56640,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56666,7 +56666,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56692,7 +56692,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56718,7 +56718,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56744,7 +56744,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56770,7 +56770,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56796,7 +56796,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56822,7 +56822,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56848,7 +56848,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56874,7 +56874,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56900,7 +56900,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56926,7 +56926,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56952,7 +56952,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56978,7 +56978,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57004,7 +57004,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57030,7 +57030,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57056,7 +57056,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57082,7 +57082,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57108,7 +57108,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57134,7 +57134,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57160,7 +57160,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57186,7 +57186,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57212,7 +57212,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57238,7 +57238,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57264,7 +57264,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57290,7 +57290,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57316,7 +57316,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57342,7 +57342,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57368,7 +57368,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57394,7 +57394,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57420,7 +57420,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57446,7 +57446,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57472,7 +57472,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57498,7 +57498,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57524,7 +57524,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57550,7 +57550,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57576,7 +57576,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57602,7 +57602,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57628,7 +57628,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57654,7 +57654,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57680,7 +57680,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57706,7 +57706,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57732,7 +57732,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57758,7 +57758,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -57784,7 +57784,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -57852,7 +57852,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -57920,7 +57920,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -57988,7 +57988,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -58056,7 +58056,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -58124,7 +58124,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -58192,7 +58192,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -58301,7 +58301,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58327,7 +58327,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58353,7 +58353,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58379,7 +58379,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58405,7 +58405,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58431,7 +58431,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58457,7 +58457,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58483,7 +58483,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58509,7 +58509,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58535,7 +58535,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58561,7 +58561,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58587,7 +58587,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58613,7 +58613,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58639,7 +58639,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58665,7 +58665,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58691,7 +58691,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58717,7 +58717,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58743,7 +58743,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58769,7 +58769,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58795,7 +58795,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58821,7 +58821,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58847,7 +58847,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58873,7 +58873,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58899,7 +58899,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58925,7 +58925,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58951,7 +58951,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58977,7 +58977,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59003,7 +59003,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59029,7 +59029,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59055,7 +59055,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59081,7 +59081,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59107,7 +59107,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59133,7 +59133,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59159,7 +59159,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59185,7 +59185,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59211,7 +59211,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59237,7 +59237,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59263,7 +59263,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59289,7 +59289,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59315,7 +59315,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59341,7 +59341,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59367,7 +59367,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59393,7 +59393,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59419,7 +59419,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59445,7 +59445,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59471,7 +59471,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59497,7 +59497,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59523,7 +59523,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59549,7 +59549,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59575,7 +59575,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59601,7 +59601,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59627,7 +59627,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59653,7 +59653,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59679,7 +59679,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59705,7 +59705,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59731,7 +59731,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59757,7 +59757,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59783,7 +59783,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59809,7 +59809,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59835,7 +59835,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59861,7 +59861,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -59929,7 +59929,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -59997,7 +59997,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -60065,7 +60065,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -60133,7 +60133,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -60201,7 +60201,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -60269,7 +60269,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -60378,7 +60378,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60404,7 +60404,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60430,7 +60430,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60456,7 +60456,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60482,7 +60482,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60508,7 +60508,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60534,7 +60534,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60560,7 +60560,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60586,7 +60586,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60612,7 +60612,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60638,7 +60638,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60664,7 +60664,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60690,7 +60690,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60716,7 +60716,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60742,7 +60742,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60768,7 +60768,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60794,7 +60794,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60820,7 +60820,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60846,7 +60846,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60872,7 +60872,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60898,7 +60898,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60924,7 +60924,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60950,7 +60950,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60976,7 +60976,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61002,7 +61002,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61028,7 +61028,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61054,7 +61054,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61080,7 +61080,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61106,7 +61106,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61132,7 +61132,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61158,7 +61158,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61184,7 +61184,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61210,7 +61210,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61236,7 +61236,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61262,7 +61262,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61288,7 +61288,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61314,7 +61314,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61340,7 +61340,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61366,7 +61366,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61392,7 +61392,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61418,7 +61418,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61444,7 +61444,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61470,7 +61470,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61496,7 +61496,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61522,7 +61522,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61548,7 +61548,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61574,7 +61574,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61600,7 +61600,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61626,7 +61626,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61652,7 +61652,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61678,7 +61678,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61704,7 +61704,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61730,7 +61730,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61756,7 +61756,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61782,7 +61782,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61808,7 +61808,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61834,7 +61834,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61860,7 +61860,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61886,7 +61886,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61912,7 +61912,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -61938,7 +61938,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -62006,7 +62006,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -62074,7 +62074,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -62142,7 +62142,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -62210,7 +62210,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -62278,7 +62278,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -62346,7 +62346,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -62455,7 +62455,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -62481,7 +62481,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -62507,7 +62507,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -62533,7 +62533,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -62559,7 +62559,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -62585,7 +62585,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -62611,7 +62611,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -62637,7 +62637,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -62663,7 +62663,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -62689,7 +62689,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -62715,7 +62715,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -62741,7 +62741,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -62767,7 +62767,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -62793,7 +62793,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -62819,7 +62819,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -62845,7 +62845,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -62871,7 +62871,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -62897,7 +62897,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -62923,7 +62923,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -62949,7 +62949,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -62975,7 +62975,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63001,7 +63001,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63027,7 +63027,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63053,7 +63053,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63079,7 +63079,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63105,7 +63105,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63131,7 +63131,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63157,7 +63157,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63183,7 +63183,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63209,7 +63209,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63235,7 +63235,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63261,7 +63261,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63287,7 +63287,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63313,7 +63313,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63339,7 +63339,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63365,7 +63365,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63391,7 +63391,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63417,7 +63417,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63443,7 +63443,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63469,7 +63469,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63495,7 +63495,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63521,7 +63521,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63547,7 +63547,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63573,7 +63573,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63599,7 +63599,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63625,7 +63625,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63651,7 +63651,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63677,7 +63677,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63703,7 +63703,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63729,7 +63729,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63755,7 +63755,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63781,7 +63781,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63807,7 +63807,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63833,7 +63833,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63859,7 +63859,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63885,7 +63885,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63911,7 +63911,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63937,7 +63937,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63963,7 +63963,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -63989,7 +63989,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -64015,7 +64015,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -64083,7 +64083,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -64151,7 +64151,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -64219,7 +64219,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -64287,7 +64287,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -64355,7 +64355,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -64423,7 +64423,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -64532,7 +64532,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -64558,7 +64558,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -64584,7 +64584,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -64610,7 +64610,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -64636,7 +64636,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -64662,7 +64662,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -64688,7 +64688,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -64714,7 +64714,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -64740,7 +64740,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -64766,7 +64766,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -64792,7 +64792,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -64818,7 +64818,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -64844,7 +64844,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -64870,7 +64870,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -64896,7 +64896,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -64922,7 +64922,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -64948,7 +64948,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -64974,7 +64974,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65000,7 +65000,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65026,7 +65026,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65052,7 +65052,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65078,7 +65078,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65104,7 +65104,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65130,7 +65130,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65156,7 +65156,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65182,7 +65182,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65208,7 +65208,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65234,7 +65234,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65260,7 +65260,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65286,7 +65286,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65312,7 +65312,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65338,7 +65338,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65364,7 +65364,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65390,7 +65390,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65416,7 +65416,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65442,7 +65442,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65468,7 +65468,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65494,7 +65494,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65520,7 +65520,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65546,7 +65546,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65572,7 +65572,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65598,7 +65598,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65624,7 +65624,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65650,7 +65650,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65676,7 +65676,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65702,7 +65702,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65728,7 +65728,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65754,7 +65754,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65780,7 +65780,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65806,7 +65806,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65832,7 +65832,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65858,7 +65858,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65884,7 +65884,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65910,7 +65910,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65936,7 +65936,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65962,7 +65962,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -65988,7 +65988,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -66014,7 +66014,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -66040,7 +66040,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -66066,7 +66066,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -66092,7 +66092,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -66160,7 +66160,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -66228,7 +66228,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -66296,7 +66296,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -66364,7 +66364,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -66432,7 +66432,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -66500,7 +66500,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -66609,7 +66609,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -66635,7 +66635,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -66661,7 +66661,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -66687,7 +66687,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -66713,7 +66713,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -66739,7 +66739,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -66765,7 +66765,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -66791,7 +66791,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -66817,7 +66817,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -66843,7 +66843,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -66869,7 +66869,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -66895,7 +66895,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -66921,7 +66921,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -66947,7 +66947,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -66973,7 +66973,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -66999,7 +66999,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67025,7 +67025,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67051,7 +67051,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67077,7 +67077,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67103,7 +67103,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67129,7 +67129,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67155,7 +67155,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67181,7 +67181,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67207,7 +67207,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67233,7 +67233,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67259,7 +67259,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67285,7 +67285,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67311,7 +67311,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67337,7 +67337,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67363,7 +67363,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67389,7 +67389,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67415,7 +67415,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67441,7 +67441,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67467,7 +67467,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67493,7 +67493,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67519,7 +67519,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67545,7 +67545,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67571,7 +67571,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67597,7 +67597,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67623,7 +67623,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67649,7 +67649,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67675,7 +67675,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67701,7 +67701,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67727,7 +67727,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67753,7 +67753,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67779,7 +67779,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67805,7 +67805,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67831,7 +67831,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67857,7 +67857,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67883,7 +67883,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67909,7 +67909,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67935,7 +67935,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67961,7 +67961,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67987,7 +67987,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -68013,7 +68013,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -68039,7 +68039,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -68065,7 +68065,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -68091,7 +68091,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -68117,7 +68117,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -68143,7 +68143,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -68169,7 +68169,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -68237,7 +68237,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -68305,7 +68305,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -68373,7 +68373,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -68441,7 +68441,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -68509,7 +68509,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -68577,7 +68577,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -68686,7 +68686,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -68712,7 +68712,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -68738,7 +68738,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -68764,7 +68764,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -68790,7 +68790,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -68816,7 +68816,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -68842,7 +68842,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -68868,7 +68868,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -68894,7 +68894,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -68920,7 +68920,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -68946,7 +68946,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -68972,7 +68972,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -68998,7 +68998,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69024,7 +69024,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69050,7 +69050,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69076,7 +69076,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69102,7 +69102,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69128,7 +69128,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69154,7 +69154,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69180,7 +69180,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69206,7 +69206,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69232,7 +69232,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69258,7 +69258,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69284,7 +69284,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69310,7 +69310,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69336,7 +69336,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69362,7 +69362,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69388,7 +69388,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69414,7 +69414,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69440,7 +69440,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69466,7 +69466,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69492,7 +69492,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69518,7 +69518,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69544,7 +69544,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69570,7 +69570,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69596,7 +69596,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69622,7 +69622,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69648,7 +69648,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69674,7 +69674,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69700,7 +69700,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69726,7 +69726,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69752,7 +69752,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69778,7 +69778,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69804,7 +69804,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69830,7 +69830,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69856,7 +69856,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69882,7 +69882,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69908,7 +69908,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69934,7 +69934,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69960,7 +69960,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69986,7 +69986,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -70012,7 +70012,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -70038,7 +70038,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -70064,7 +70064,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -70090,7 +70090,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -70116,7 +70116,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -70142,7 +70142,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -70168,7 +70168,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -70194,7 +70194,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -70220,7 +70220,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -70246,7 +70246,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -70314,7 +70314,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -70382,7 +70382,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -70450,7 +70450,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -70518,7 +70518,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -70586,7 +70586,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -70654,7 +70654,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -70763,7 +70763,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -70789,7 +70789,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -70815,7 +70815,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -70841,7 +70841,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -70867,7 +70867,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -70893,7 +70893,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -70919,7 +70919,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -70945,7 +70945,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -70971,7 +70971,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -70997,7 +70997,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71023,7 +71023,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71049,7 +71049,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71075,7 +71075,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71101,7 +71101,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71127,7 +71127,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71153,7 +71153,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71179,7 +71179,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71205,7 +71205,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71231,7 +71231,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71257,7 +71257,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71283,7 +71283,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71309,7 +71309,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71335,7 +71335,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71361,7 +71361,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71387,7 +71387,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71413,7 +71413,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71439,7 +71439,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71465,7 +71465,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71491,7 +71491,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71517,7 +71517,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71543,7 +71543,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71569,7 +71569,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71595,7 +71595,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71621,7 +71621,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71647,7 +71647,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71673,7 +71673,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71699,7 +71699,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71725,7 +71725,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71751,7 +71751,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71777,7 +71777,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71803,7 +71803,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71829,7 +71829,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71855,7 +71855,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71881,7 +71881,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71907,7 +71907,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71933,7 +71933,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71959,7 +71959,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71985,7 +71985,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -72011,7 +72011,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -72037,7 +72037,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -72063,7 +72063,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -72089,7 +72089,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -72115,7 +72115,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -72141,7 +72141,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -72167,7 +72167,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -72193,7 +72193,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -72219,7 +72219,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -72245,7 +72245,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -72271,7 +72271,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -72297,7 +72297,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -72323,7 +72323,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -72391,7 +72391,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -72459,7 +72459,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -72527,7 +72527,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -72595,7 +72595,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -72663,7 +72663,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -72731,7 +72731,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -72846,7 +72846,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -72872,7 +72872,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -72898,7 +72898,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -72924,7 +72924,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -72950,7 +72950,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -72976,7 +72976,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -73002,7 +73002,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -73028,7 +73028,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -73104,7 +73104,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -73130,7 +73130,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -73156,7 +73156,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -73182,7 +73182,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -73208,7 +73208,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -73234,7 +73234,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -73260,7 +73260,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -73286,7 +73286,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -73392,7 +73392,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -73418,7 +73418,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -73527,7 +73527,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -73553,7 +73553,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -73692,7 +73692,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -73718,7 +73718,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -73827,7 +73827,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -73853,7 +73853,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -73962,7 +73962,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -73988,7 +73988,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -74097,7 +74097,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -74123,7 +74123,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -74232,7 +74232,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -74258,7 +74258,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -74367,7 +74367,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -74393,7 +74393,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -74556,7 +74556,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -74582,7 +74582,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -74608,7 +74608,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -74634,7 +74634,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -74660,7 +74660,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -74686,7 +74686,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -74712,7 +74712,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -74738,7 +74738,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -74764,7 +74764,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -74790,7 +74790,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -74816,7 +74816,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -74842,7 +74842,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -74868,7 +74868,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -74894,7 +74894,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -74920,7 +74920,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -74946,7 +74946,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -74972,7 +74972,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -74998,7 +74998,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75024,7 +75024,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75050,7 +75050,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75076,7 +75076,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75102,7 +75102,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75128,7 +75128,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75154,7 +75154,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75180,7 +75180,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75206,7 +75206,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75232,7 +75232,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75258,7 +75258,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75284,7 +75284,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75310,7 +75310,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75336,7 +75336,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75362,7 +75362,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75388,7 +75388,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75414,7 +75414,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75440,7 +75440,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75466,7 +75466,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75492,7 +75492,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75518,7 +75518,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75544,7 +75544,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75570,7 +75570,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75596,7 +75596,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75622,7 +75622,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75648,7 +75648,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75674,7 +75674,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75700,7 +75700,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75726,7 +75726,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75752,7 +75752,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75778,7 +75778,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75804,7 +75804,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75830,7 +75830,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75856,7 +75856,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75882,7 +75882,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75908,7 +75908,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75934,7 +75934,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75960,7 +75960,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75986,7 +75986,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -76012,7 +76012,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -76038,7 +76038,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -76064,7 +76064,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -76090,7 +76090,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -76116,7 +76116,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -76184,7 +76184,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -76252,7 +76252,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -76320,7 +76320,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -76388,7 +76388,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -76456,7 +76456,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -76524,7 +76524,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -76633,7 +76633,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -76659,7 +76659,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -76685,7 +76685,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -76711,7 +76711,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -76737,7 +76737,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -76763,7 +76763,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -76789,7 +76789,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -76815,7 +76815,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -76841,7 +76841,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -76867,7 +76867,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -76893,7 +76893,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -76919,7 +76919,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -76945,7 +76945,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -76971,7 +76971,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -76997,7 +76997,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77023,7 +77023,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77049,7 +77049,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77075,7 +77075,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77101,7 +77101,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77127,7 +77127,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77153,7 +77153,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77179,7 +77179,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77205,7 +77205,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77231,7 +77231,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77257,7 +77257,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77283,7 +77283,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77309,7 +77309,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77335,7 +77335,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77361,7 +77361,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77387,7 +77387,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77413,7 +77413,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77439,7 +77439,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77465,7 +77465,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77491,7 +77491,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77517,7 +77517,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77543,7 +77543,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77569,7 +77569,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77595,7 +77595,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77621,7 +77621,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77647,7 +77647,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77673,7 +77673,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77699,7 +77699,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77725,7 +77725,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77751,7 +77751,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77777,7 +77777,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77803,7 +77803,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77829,7 +77829,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77855,7 +77855,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77881,7 +77881,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77907,7 +77907,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77933,7 +77933,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77959,7 +77959,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77985,7 +77985,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -78011,7 +78011,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -78037,7 +78037,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -78063,7 +78063,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -78089,7 +78089,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -78115,7 +78115,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -78141,7 +78141,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -78167,7 +78167,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -78193,7 +78193,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -78261,7 +78261,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -78329,7 +78329,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -78397,7 +78397,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -78465,7 +78465,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -78533,7 +78533,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -78601,7 +78601,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -78710,7 +78710,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -78736,7 +78736,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -78762,7 +78762,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -78788,7 +78788,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -78814,7 +78814,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -78840,7 +78840,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -78866,7 +78866,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -78892,7 +78892,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -78918,7 +78918,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -78944,7 +78944,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -78970,7 +78970,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -78996,7 +78996,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79022,7 +79022,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79048,7 +79048,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79074,7 +79074,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79100,7 +79100,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79126,7 +79126,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79152,7 +79152,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79178,7 +79178,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79204,7 +79204,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79230,7 +79230,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79256,7 +79256,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79282,7 +79282,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79308,7 +79308,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79334,7 +79334,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79360,7 +79360,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79386,7 +79386,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79412,7 +79412,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79438,7 +79438,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79464,7 +79464,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79490,7 +79490,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79516,7 +79516,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79542,7 +79542,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79568,7 +79568,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79594,7 +79594,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79620,7 +79620,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79646,7 +79646,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79672,7 +79672,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79698,7 +79698,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79724,7 +79724,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79750,7 +79750,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79776,7 +79776,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79802,7 +79802,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79828,7 +79828,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79854,7 +79854,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79880,7 +79880,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79906,7 +79906,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79932,7 +79932,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79958,7 +79958,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -79984,7 +79984,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -80010,7 +80010,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -80036,7 +80036,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -80062,7 +80062,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -80088,7 +80088,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -80114,7 +80114,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -80140,7 +80140,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -80166,7 +80166,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -80192,7 +80192,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -80218,7 +80218,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -80244,7 +80244,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -80270,7 +80270,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -80338,7 +80338,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -80406,7 +80406,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -80474,7 +80474,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -80542,7 +80542,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -80610,7 +80610,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -80678,7 +80678,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -80787,7 +80787,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -80813,7 +80813,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -80839,7 +80839,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -80865,7 +80865,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -80891,7 +80891,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -80917,7 +80917,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -80943,7 +80943,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -80969,7 +80969,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -80995,7 +80995,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81021,7 +81021,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81047,7 +81047,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81073,7 +81073,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81099,7 +81099,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81125,7 +81125,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81151,7 +81151,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81177,7 +81177,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81203,7 +81203,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81229,7 +81229,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81255,7 +81255,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81281,7 +81281,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81307,7 +81307,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81333,7 +81333,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81359,7 +81359,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81385,7 +81385,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81411,7 +81411,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81437,7 +81437,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81463,7 +81463,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81489,7 +81489,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81515,7 +81515,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81541,7 +81541,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81567,7 +81567,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81593,7 +81593,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81619,7 +81619,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81645,7 +81645,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81671,7 +81671,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81697,7 +81697,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81723,7 +81723,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81749,7 +81749,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81775,7 +81775,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81801,7 +81801,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81827,7 +81827,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81853,7 +81853,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81879,7 +81879,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81905,7 +81905,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81931,7 +81931,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81957,7 +81957,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81983,7 +81983,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -82009,7 +82009,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -82035,7 +82035,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -82061,7 +82061,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -82087,7 +82087,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -82113,7 +82113,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -82139,7 +82139,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -82165,7 +82165,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -82191,7 +82191,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -82217,7 +82217,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -82243,7 +82243,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -82269,7 +82269,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -82295,7 +82295,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -82321,7 +82321,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -82347,7 +82347,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -82415,7 +82415,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -82483,7 +82483,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -82551,7 +82551,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -82619,7 +82619,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -82687,7 +82687,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -82755,7 +82755,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -82864,7 +82864,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -82890,7 +82890,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -82916,7 +82916,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -82942,7 +82942,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -82968,7 +82968,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -82994,7 +82994,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83020,7 +83020,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83046,7 +83046,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83072,7 +83072,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83098,7 +83098,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83124,7 +83124,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83150,7 +83150,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83176,7 +83176,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83202,7 +83202,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83228,7 +83228,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83254,7 +83254,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83280,7 +83280,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83306,7 +83306,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83332,7 +83332,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83358,7 +83358,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83384,7 +83384,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83410,7 +83410,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83436,7 +83436,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83462,7 +83462,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83488,7 +83488,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83514,7 +83514,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83540,7 +83540,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83566,7 +83566,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83592,7 +83592,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83618,7 +83618,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83644,7 +83644,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83670,7 +83670,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83696,7 +83696,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83722,7 +83722,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83748,7 +83748,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83774,7 +83774,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83800,7 +83800,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83826,7 +83826,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83852,7 +83852,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83878,7 +83878,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83904,7 +83904,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83930,7 +83930,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83956,7 +83956,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -83982,7 +83982,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84008,7 +84008,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84034,7 +84034,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84060,7 +84060,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84086,7 +84086,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84112,7 +84112,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84138,7 +84138,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84164,7 +84164,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84190,7 +84190,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84216,7 +84216,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84242,7 +84242,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84268,7 +84268,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84294,7 +84294,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84320,7 +84320,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84346,7 +84346,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84372,7 +84372,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84398,7 +84398,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84424,7 +84424,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -84492,7 +84492,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -84560,7 +84560,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -84628,7 +84628,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -84696,7 +84696,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -84764,7 +84764,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -84832,7 +84832,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -84941,7 +84941,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84967,7 +84967,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84993,7 +84993,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85019,7 +85019,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85045,7 +85045,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85071,7 +85071,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85097,7 +85097,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85123,7 +85123,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85149,7 +85149,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85175,7 +85175,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85201,7 +85201,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85227,7 +85227,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85253,7 +85253,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85279,7 +85279,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85305,7 +85305,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85331,7 +85331,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85357,7 +85357,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85383,7 +85383,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85409,7 +85409,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85435,7 +85435,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85461,7 +85461,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85487,7 +85487,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85513,7 +85513,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85539,7 +85539,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85565,7 +85565,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85591,7 +85591,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85617,7 +85617,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85643,7 +85643,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85669,7 +85669,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85695,7 +85695,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85721,7 +85721,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85747,7 +85747,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85773,7 +85773,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85799,7 +85799,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85825,7 +85825,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85851,7 +85851,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85877,7 +85877,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85903,7 +85903,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85929,7 +85929,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85955,7 +85955,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85981,7 +85981,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -86007,7 +86007,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -86033,7 +86033,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -86059,7 +86059,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -86085,7 +86085,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -86111,7 +86111,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -86137,7 +86137,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -86163,7 +86163,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -86189,7 +86189,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -86215,7 +86215,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -86241,7 +86241,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -86267,7 +86267,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -86293,7 +86293,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -86319,7 +86319,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -86345,7 +86345,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -86371,7 +86371,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -86397,7 +86397,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -86423,7 +86423,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -86449,7 +86449,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -86475,7 +86475,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -86501,7 +86501,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -86569,7 +86569,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -86637,7 +86637,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -86705,7 +86705,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -86773,7 +86773,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -86841,7 +86841,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -86909,7 +86909,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -87018,7 +87018,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87044,7 +87044,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87070,7 +87070,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87096,7 +87096,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87122,7 +87122,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87148,7 +87148,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87174,7 +87174,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87200,7 +87200,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87226,7 +87226,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87252,7 +87252,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87278,7 +87278,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87304,7 +87304,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87330,7 +87330,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87356,7 +87356,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87382,7 +87382,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87408,7 +87408,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87434,7 +87434,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87460,7 +87460,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87486,7 +87486,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87512,7 +87512,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87538,7 +87538,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87564,7 +87564,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87590,7 +87590,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87616,7 +87616,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87642,7 +87642,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87668,7 +87668,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87694,7 +87694,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87720,7 +87720,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87746,7 +87746,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87772,7 +87772,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87798,7 +87798,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87824,7 +87824,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87850,7 +87850,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87876,7 +87876,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87902,7 +87902,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87928,7 +87928,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87954,7 +87954,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87980,7 +87980,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88006,7 +88006,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88032,7 +88032,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88058,7 +88058,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88084,7 +88084,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88110,7 +88110,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88136,7 +88136,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88162,7 +88162,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88188,7 +88188,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88214,7 +88214,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88240,7 +88240,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88266,7 +88266,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88292,7 +88292,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88318,7 +88318,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88344,7 +88344,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88370,7 +88370,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88396,7 +88396,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88422,7 +88422,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88448,7 +88448,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88474,7 +88474,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88500,7 +88500,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88526,7 +88526,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88552,7 +88552,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88578,7 +88578,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -88646,7 +88646,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -88714,7 +88714,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -88782,7 +88782,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -88850,7 +88850,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -88918,7 +88918,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -88986,7 +88986,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -89095,7 +89095,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89121,7 +89121,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89147,7 +89147,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89173,7 +89173,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89199,7 +89199,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89225,7 +89225,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89251,7 +89251,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89277,7 +89277,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89303,7 +89303,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89329,7 +89329,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89355,7 +89355,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89381,7 +89381,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89407,7 +89407,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89433,7 +89433,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89459,7 +89459,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89485,7 +89485,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89511,7 +89511,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89537,7 +89537,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89563,7 +89563,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89589,7 +89589,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89615,7 +89615,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89641,7 +89641,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89667,7 +89667,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89693,7 +89693,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89719,7 +89719,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89745,7 +89745,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89771,7 +89771,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89797,7 +89797,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89823,7 +89823,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89849,7 +89849,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89875,7 +89875,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89901,7 +89901,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89927,7 +89927,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89953,7 +89953,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89979,7 +89979,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90005,7 +90005,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90031,7 +90031,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90057,7 +90057,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90083,7 +90083,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90109,7 +90109,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90135,7 +90135,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90161,7 +90161,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90187,7 +90187,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90213,7 +90213,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90239,7 +90239,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90265,7 +90265,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90291,7 +90291,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90317,7 +90317,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90343,7 +90343,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90369,7 +90369,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90395,7 +90395,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90421,7 +90421,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90447,7 +90447,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90473,7 +90473,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90499,7 +90499,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90525,7 +90525,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90551,7 +90551,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90577,7 +90577,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90603,7 +90603,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90629,7 +90629,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90655,7 +90655,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -90723,7 +90723,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -90791,7 +90791,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -90859,7 +90859,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -90927,7 +90927,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -90995,7 +90995,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -91063,7 +91063,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -91178,7 +91178,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -91204,7 +91204,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -91230,7 +91230,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -91256,7 +91256,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -91282,7 +91282,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -91308,7 +91308,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -91334,7 +91334,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -91360,7 +91360,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -91436,7 +91436,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -91462,7 +91462,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -91488,7 +91488,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -91514,7 +91514,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -91540,7 +91540,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -91566,7 +91566,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -91592,7 +91592,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -91618,7 +91618,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -91724,7 +91724,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -91750,7 +91750,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -91859,7 +91859,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -91885,7 +91885,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -92024,7 +92024,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -92050,7 +92050,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -92159,7 +92159,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -92185,7 +92185,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -92294,7 +92294,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -92320,7 +92320,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -92429,7 +92429,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -92455,7 +92455,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -92564,7 +92564,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -92590,7 +92590,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -92699,7 +92699,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -92725,7 +92725,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -92888,7 +92888,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -92914,7 +92914,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -92940,7 +92940,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -92966,7 +92966,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -92992,7 +92992,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93018,7 +93018,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93044,7 +93044,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93070,7 +93070,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93096,7 +93096,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93122,7 +93122,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93148,7 +93148,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93174,7 +93174,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93200,7 +93200,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93226,7 +93226,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93252,7 +93252,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93278,7 +93278,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93304,7 +93304,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93330,7 +93330,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93356,7 +93356,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93382,7 +93382,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93408,7 +93408,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93434,7 +93434,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93460,7 +93460,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93486,7 +93486,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93512,7 +93512,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93538,7 +93538,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93564,7 +93564,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93590,7 +93590,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93616,7 +93616,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93642,7 +93642,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93668,7 +93668,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93694,7 +93694,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93720,7 +93720,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93746,7 +93746,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93772,7 +93772,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93798,7 +93798,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93824,7 +93824,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93850,7 +93850,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93876,7 +93876,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93902,7 +93902,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93928,7 +93928,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93954,7 +93954,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -93980,7 +93980,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -94006,7 +94006,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -94032,7 +94032,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -94058,7 +94058,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -94084,7 +94084,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -94110,7 +94110,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -94136,7 +94136,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -94162,7 +94162,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -94188,7 +94188,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -94214,7 +94214,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -94240,7 +94240,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -94266,7 +94266,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -94292,7 +94292,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -94318,7 +94318,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -94344,7 +94344,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -94370,7 +94370,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -94396,7 +94396,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -94422,7 +94422,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -94448,7 +94448,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -94516,7 +94516,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -94584,7 +94584,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -94652,7 +94652,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -94720,7 +94720,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -94788,7 +94788,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -94856,7 +94856,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -94965,7 +94965,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -94991,7 +94991,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95017,7 +95017,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95043,7 +95043,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95069,7 +95069,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95095,7 +95095,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95121,7 +95121,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95147,7 +95147,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95173,7 +95173,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95199,7 +95199,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95225,7 +95225,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95251,7 +95251,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95277,7 +95277,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95303,7 +95303,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95329,7 +95329,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95355,7 +95355,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95381,7 +95381,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95407,7 +95407,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95433,7 +95433,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95459,7 +95459,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95485,7 +95485,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95511,7 +95511,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95537,7 +95537,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95563,7 +95563,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95589,7 +95589,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95615,7 +95615,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95641,7 +95641,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95667,7 +95667,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95693,7 +95693,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95719,7 +95719,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95745,7 +95745,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95771,7 +95771,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95797,7 +95797,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95823,7 +95823,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95849,7 +95849,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95875,7 +95875,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95901,7 +95901,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95927,7 +95927,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95953,7 +95953,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95979,7 +95979,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -96005,7 +96005,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -96031,7 +96031,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -96057,7 +96057,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -96083,7 +96083,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -96109,7 +96109,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -96135,7 +96135,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -96161,7 +96161,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -96187,7 +96187,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -96213,7 +96213,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -96239,7 +96239,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -96265,7 +96265,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -96291,7 +96291,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -96317,7 +96317,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -96343,7 +96343,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -96369,7 +96369,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -96395,7 +96395,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -96421,7 +96421,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -96447,7 +96447,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -96473,7 +96473,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -96499,7 +96499,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -96525,7 +96525,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -96593,7 +96593,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -96661,7 +96661,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -96729,7 +96729,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -96797,7 +96797,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -96865,7 +96865,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -96933,7 +96933,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -97042,7 +97042,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97068,7 +97068,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97094,7 +97094,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97120,7 +97120,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97146,7 +97146,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97172,7 +97172,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97198,7 +97198,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97224,7 +97224,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97250,7 +97250,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97276,7 +97276,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97302,7 +97302,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97328,7 +97328,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97354,7 +97354,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97380,7 +97380,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97406,7 +97406,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97432,7 +97432,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97458,7 +97458,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97484,7 +97484,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97510,7 +97510,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97536,7 +97536,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97562,7 +97562,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97588,7 +97588,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97614,7 +97614,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97640,7 +97640,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97666,7 +97666,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97692,7 +97692,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97718,7 +97718,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97744,7 +97744,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97770,7 +97770,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97796,7 +97796,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97822,7 +97822,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97848,7 +97848,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97874,7 +97874,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97900,7 +97900,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97926,7 +97926,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97952,7 +97952,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97978,7 +97978,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98004,7 +98004,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98030,7 +98030,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98056,7 +98056,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98082,7 +98082,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98108,7 +98108,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98134,7 +98134,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98160,7 +98160,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98186,7 +98186,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98212,7 +98212,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98238,7 +98238,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98264,7 +98264,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98290,7 +98290,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98316,7 +98316,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98342,7 +98342,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98368,7 +98368,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98394,7 +98394,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98420,7 +98420,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98446,7 +98446,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98472,7 +98472,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98498,7 +98498,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98524,7 +98524,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98550,7 +98550,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98576,7 +98576,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98602,7 +98602,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -98670,7 +98670,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -98738,7 +98738,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -98806,7 +98806,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -98874,7 +98874,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -98942,7 +98942,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -99010,7 +99010,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -99119,7 +99119,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99145,7 +99145,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99171,7 +99171,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99197,7 +99197,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99223,7 +99223,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99249,7 +99249,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99275,7 +99275,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99301,7 +99301,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99327,7 +99327,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99353,7 +99353,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99379,7 +99379,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99405,7 +99405,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99431,7 +99431,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99457,7 +99457,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99483,7 +99483,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99509,7 +99509,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99535,7 +99535,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99561,7 +99561,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99587,7 +99587,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99613,7 +99613,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99639,7 +99639,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99665,7 +99665,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99691,7 +99691,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99717,7 +99717,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99743,7 +99743,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99769,7 +99769,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99795,7 +99795,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99821,7 +99821,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99847,7 +99847,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99873,7 +99873,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99899,7 +99899,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99925,7 +99925,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99951,7 +99951,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99977,7 +99977,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100003,7 +100003,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100029,7 +100029,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100055,7 +100055,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100081,7 +100081,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100107,7 +100107,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100133,7 +100133,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100159,7 +100159,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100185,7 +100185,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100211,7 +100211,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100237,7 +100237,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100263,7 +100263,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100289,7 +100289,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100315,7 +100315,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100341,7 +100341,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100367,7 +100367,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100393,7 +100393,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100419,7 +100419,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100445,7 +100445,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100471,7 +100471,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100497,7 +100497,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100523,7 +100523,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100549,7 +100549,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100575,7 +100575,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100601,7 +100601,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100627,7 +100627,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100653,7 +100653,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -100679,7 +100679,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -100747,7 +100747,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -100815,7 +100815,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -100883,7 +100883,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -100951,7 +100951,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -101019,7 +101019,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -101087,7 +101087,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -101196,7 +101196,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101222,7 +101222,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101248,7 +101248,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101274,7 +101274,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101300,7 +101300,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101326,7 +101326,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101352,7 +101352,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101378,7 +101378,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101404,7 +101404,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101430,7 +101430,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101456,7 +101456,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101482,7 +101482,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101508,7 +101508,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101534,7 +101534,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101560,7 +101560,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101586,7 +101586,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101612,7 +101612,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101638,7 +101638,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101664,7 +101664,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101690,7 +101690,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101716,7 +101716,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101742,7 +101742,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101768,7 +101768,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101794,7 +101794,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101820,7 +101820,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101846,7 +101846,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101872,7 +101872,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101898,7 +101898,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101924,7 +101924,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101950,7 +101950,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -101976,7 +101976,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102002,7 +102002,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102028,7 +102028,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102054,7 +102054,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102080,7 +102080,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102106,7 +102106,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102132,7 +102132,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102158,7 +102158,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102184,7 +102184,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102210,7 +102210,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102236,7 +102236,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102262,7 +102262,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102288,7 +102288,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102314,7 +102314,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102340,7 +102340,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102366,7 +102366,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102392,7 +102392,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102418,7 +102418,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102444,7 +102444,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102470,7 +102470,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102496,7 +102496,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102522,7 +102522,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102548,7 +102548,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102574,7 +102574,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102600,7 +102600,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102626,7 +102626,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102652,7 +102652,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102678,7 +102678,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102704,7 +102704,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102730,7 +102730,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -102756,7 +102756,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -102824,7 +102824,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -102892,7 +102892,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -102960,7 +102960,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -103028,7 +103028,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -103096,7 +103096,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -103164,7 +103164,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -103273,7 +103273,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103299,7 +103299,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103325,7 +103325,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103351,7 +103351,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103377,7 +103377,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103403,7 +103403,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103429,7 +103429,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103455,7 +103455,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103481,7 +103481,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103507,7 +103507,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103533,7 +103533,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103559,7 +103559,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103585,7 +103585,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103611,7 +103611,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103637,7 +103637,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103663,7 +103663,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103689,7 +103689,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103715,7 +103715,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103741,7 +103741,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103767,7 +103767,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103793,7 +103793,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103819,7 +103819,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103845,7 +103845,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103871,7 +103871,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103897,7 +103897,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103923,7 +103923,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103949,7 +103949,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -103975,7 +103975,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104001,7 +104001,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104027,7 +104027,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104053,7 +104053,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104079,7 +104079,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104105,7 +104105,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104131,7 +104131,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104157,7 +104157,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104183,7 +104183,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104209,7 +104209,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104235,7 +104235,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104261,7 +104261,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104287,7 +104287,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104313,7 +104313,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104339,7 +104339,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104365,7 +104365,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104391,7 +104391,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104417,7 +104417,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104443,7 +104443,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104469,7 +104469,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104495,7 +104495,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104521,7 +104521,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104547,7 +104547,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104573,7 +104573,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104599,7 +104599,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104625,7 +104625,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104651,7 +104651,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104677,7 +104677,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104703,7 +104703,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104729,7 +104729,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104755,7 +104755,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104781,7 +104781,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104807,7 +104807,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -104833,7 +104833,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -104901,7 +104901,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -104969,7 +104969,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -105037,7 +105037,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -105105,7 +105105,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -105173,7 +105173,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -105241,7 +105241,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -105350,7 +105350,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105376,7 +105376,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105402,7 +105402,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105428,7 +105428,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105454,7 +105454,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105480,7 +105480,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105506,7 +105506,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105532,7 +105532,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105558,7 +105558,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105584,7 +105584,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105610,7 +105610,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105636,7 +105636,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105662,7 +105662,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105688,7 +105688,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105714,7 +105714,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105740,7 +105740,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105766,7 +105766,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105792,7 +105792,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105818,7 +105818,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105844,7 +105844,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105870,7 +105870,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105896,7 +105896,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105922,7 +105922,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105948,7 +105948,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -105974,7 +105974,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106000,7 +106000,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106026,7 +106026,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106052,7 +106052,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106078,7 +106078,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106104,7 +106104,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106130,7 +106130,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106156,7 +106156,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106182,7 +106182,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106208,7 +106208,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106234,7 +106234,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106260,7 +106260,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106286,7 +106286,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106312,7 +106312,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106338,7 +106338,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106364,7 +106364,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106390,7 +106390,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106416,7 +106416,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106442,7 +106442,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106468,7 +106468,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106494,7 +106494,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106520,7 +106520,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106546,7 +106546,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106572,7 +106572,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106598,7 +106598,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106624,7 +106624,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106650,7 +106650,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106676,7 +106676,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106702,7 +106702,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106728,7 +106728,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106754,7 +106754,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106780,7 +106780,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106806,7 +106806,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106832,7 +106832,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106858,7 +106858,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106884,7 +106884,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -106910,7 +106910,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -106978,7 +106978,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -107046,7 +107046,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -107114,7 +107114,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -107182,7 +107182,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -107250,7 +107250,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -107318,7 +107318,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -107427,7 +107427,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -107453,7 +107453,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -107479,7 +107479,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -107505,7 +107505,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -107531,7 +107531,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -107557,7 +107557,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -107583,7 +107583,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -107609,7 +107609,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -107635,7 +107635,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -107661,7 +107661,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -107687,7 +107687,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -107713,7 +107713,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -107739,7 +107739,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -107765,7 +107765,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -107791,7 +107791,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -107817,7 +107817,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -107843,7 +107843,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -107869,7 +107869,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -107895,7 +107895,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -107921,7 +107921,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -107947,7 +107947,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -107973,7 +107973,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -107999,7 +107999,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108025,7 +108025,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108051,7 +108051,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108077,7 +108077,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108103,7 +108103,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108129,7 +108129,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108155,7 +108155,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108181,7 +108181,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108207,7 +108207,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108233,7 +108233,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108259,7 +108259,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108285,7 +108285,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108311,7 +108311,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108337,7 +108337,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108363,7 +108363,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108389,7 +108389,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108415,7 +108415,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108441,7 +108441,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108467,7 +108467,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108493,7 +108493,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108519,7 +108519,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108545,7 +108545,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108571,7 +108571,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108597,7 +108597,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108623,7 +108623,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108649,7 +108649,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108675,7 +108675,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108701,7 +108701,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108727,7 +108727,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108753,7 +108753,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108779,7 +108779,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108805,7 +108805,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108831,7 +108831,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108857,7 +108857,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108883,7 +108883,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108909,7 +108909,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108935,7 +108935,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108961,7 +108961,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -108987,7 +108987,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -109055,7 +109055,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -109123,7 +109123,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -109191,7 +109191,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -109259,7 +109259,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -109327,7 +109327,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -109395,7 +109395,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -109510,7 +109510,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -109536,7 +109536,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -109562,7 +109562,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -109588,7 +109588,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -109614,7 +109614,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -109640,7 +109640,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -109666,7 +109666,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -109692,7 +109692,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -109768,7 +109768,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -109794,7 +109794,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -109820,7 +109820,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -109846,7 +109846,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -109872,7 +109872,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -109898,7 +109898,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -109924,7 +109924,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -109950,7 +109950,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -110056,7 +110056,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -110082,7 +110082,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -110191,7 +110191,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -110217,7 +110217,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -110356,7 +110356,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -110382,7 +110382,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -110491,7 +110491,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -110517,7 +110517,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -110626,7 +110626,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -110652,7 +110652,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -110761,7 +110761,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -110787,7 +110787,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -110896,7 +110896,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -110922,7 +110922,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -111031,7 +111031,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -111057,7 +111057,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -111220,7 +111220,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111246,7 +111246,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111272,7 +111272,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111298,7 +111298,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111324,7 +111324,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111350,7 +111350,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111376,7 +111376,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111402,7 +111402,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111428,7 +111428,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111454,7 +111454,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111480,7 +111480,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111506,7 +111506,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111532,7 +111532,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111558,7 +111558,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111584,7 +111584,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111610,7 +111610,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111636,7 +111636,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111662,7 +111662,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111688,7 +111688,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111714,7 +111714,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111740,7 +111740,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111766,7 +111766,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111792,7 +111792,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111818,7 +111818,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111844,7 +111844,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111870,7 +111870,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111896,7 +111896,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111922,7 +111922,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111948,7 +111948,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -111974,7 +111974,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112000,7 +112000,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112026,7 +112026,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112052,7 +112052,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112078,7 +112078,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112104,7 +112104,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112130,7 +112130,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112156,7 +112156,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112182,7 +112182,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112208,7 +112208,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112234,7 +112234,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112260,7 +112260,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112286,7 +112286,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112312,7 +112312,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112338,7 +112338,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112364,7 +112364,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112390,7 +112390,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112416,7 +112416,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112442,7 +112442,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112468,7 +112468,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112494,7 +112494,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112520,7 +112520,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112546,7 +112546,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112572,7 +112572,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112598,7 +112598,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112624,7 +112624,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112650,7 +112650,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112676,7 +112676,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112702,7 +112702,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112728,7 +112728,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112754,7 +112754,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -112780,7 +112780,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -112848,7 +112848,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -112916,7 +112916,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -112984,7 +112984,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -113052,7 +113052,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -113120,7 +113120,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -113188,7 +113188,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -113297,7 +113297,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113323,7 +113323,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113349,7 +113349,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113375,7 +113375,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113401,7 +113401,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113427,7 +113427,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113453,7 +113453,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113479,7 +113479,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113505,7 +113505,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113531,7 +113531,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113557,7 +113557,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113583,7 +113583,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113609,7 +113609,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113635,7 +113635,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113661,7 +113661,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113687,7 +113687,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113713,7 +113713,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113739,7 +113739,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113765,7 +113765,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113791,7 +113791,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113817,7 +113817,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113843,7 +113843,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113869,7 +113869,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113895,7 +113895,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113921,7 +113921,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113947,7 +113947,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113973,7 +113973,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -113999,7 +113999,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114025,7 +114025,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114051,7 +114051,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114077,7 +114077,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114103,7 +114103,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114129,7 +114129,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114155,7 +114155,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114181,7 +114181,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114207,7 +114207,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114233,7 +114233,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114259,7 +114259,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114285,7 +114285,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114311,7 +114311,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114337,7 +114337,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114363,7 +114363,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114389,7 +114389,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114415,7 +114415,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114441,7 +114441,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114467,7 +114467,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114493,7 +114493,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114519,7 +114519,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114545,7 +114545,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114571,7 +114571,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114597,7 +114597,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114623,7 +114623,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114649,7 +114649,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114675,7 +114675,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114701,7 +114701,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114727,7 +114727,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114753,7 +114753,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114779,7 +114779,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114805,7 +114805,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114831,7 +114831,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -114857,7 +114857,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -114925,7 +114925,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -114993,7 +114993,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -115061,7 +115061,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -115129,7 +115129,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -115197,7 +115197,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -115265,7 +115265,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -115374,7 +115374,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115400,7 +115400,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115426,7 +115426,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115452,7 +115452,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115478,7 +115478,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115504,7 +115504,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115530,7 +115530,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115556,7 +115556,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115582,7 +115582,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115608,7 +115608,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115634,7 +115634,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115660,7 +115660,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115686,7 +115686,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115712,7 +115712,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115738,7 +115738,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115764,7 +115764,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115790,7 +115790,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115816,7 +115816,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115842,7 +115842,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115868,7 +115868,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115894,7 +115894,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115920,7 +115920,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115946,7 +115946,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115972,7 +115972,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -115998,7 +115998,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116024,7 +116024,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116050,7 +116050,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116076,7 +116076,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116102,7 +116102,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116128,7 +116128,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116154,7 +116154,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116180,7 +116180,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116206,7 +116206,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116232,7 +116232,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116258,7 +116258,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116284,7 +116284,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116310,7 +116310,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116336,7 +116336,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116362,7 +116362,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116388,7 +116388,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116414,7 +116414,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116440,7 +116440,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116466,7 +116466,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116492,7 +116492,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116518,7 +116518,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116544,7 +116544,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116570,7 +116570,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116596,7 +116596,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116622,7 +116622,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116648,7 +116648,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116674,7 +116674,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116700,7 +116700,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116726,7 +116726,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116752,7 +116752,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116778,7 +116778,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116804,7 +116804,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116830,7 +116830,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116856,7 +116856,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116882,7 +116882,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116908,7 +116908,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -116934,7 +116934,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -117002,7 +117002,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -117070,7 +117070,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -117138,7 +117138,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -117206,7 +117206,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -117274,7 +117274,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -117342,7 +117342,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -117451,7 +117451,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -117477,7 +117477,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -117503,7 +117503,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -117529,7 +117529,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -117555,7 +117555,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -117581,7 +117581,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -117607,7 +117607,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -117633,7 +117633,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -117659,7 +117659,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -117685,7 +117685,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -117711,7 +117711,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -117737,7 +117737,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -117763,7 +117763,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -117789,7 +117789,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -117815,7 +117815,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -117841,7 +117841,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -117867,7 +117867,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -117893,7 +117893,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -117919,7 +117919,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -117945,7 +117945,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -117971,7 +117971,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -117997,7 +117997,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118023,7 +118023,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118049,7 +118049,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118075,7 +118075,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118101,7 +118101,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118127,7 +118127,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118153,7 +118153,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118179,7 +118179,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118205,7 +118205,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118231,7 +118231,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118257,7 +118257,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118283,7 +118283,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118309,7 +118309,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118335,7 +118335,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118361,7 +118361,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118387,7 +118387,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118413,7 +118413,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118439,7 +118439,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118465,7 +118465,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118491,7 +118491,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118517,7 +118517,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118543,7 +118543,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118569,7 +118569,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118595,7 +118595,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118621,7 +118621,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118647,7 +118647,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118673,7 +118673,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118699,7 +118699,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118725,7 +118725,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118751,7 +118751,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118777,7 +118777,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118803,7 +118803,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118829,7 +118829,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118855,7 +118855,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118881,7 +118881,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118907,7 +118907,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118933,7 +118933,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118959,7 +118959,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -118985,7 +118985,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -119011,7 +119011,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -119079,7 +119079,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -119147,7 +119147,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -119215,7 +119215,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -119283,7 +119283,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -119351,7 +119351,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -119419,7 +119419,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -119528,7 +119528,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -119554,7 +119554,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -119580,7 +119580,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -119606,7 +119606,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -119632,7 +119632,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -119658,7 +119658,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -119684,7 +119684,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -119710,7 +119710,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -119736,7 +119736,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -119762,7 +119762,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -119788,7 +119788,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -119814,7 +119814,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -119840,7 +119840,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -119866,7 +119866,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -119892,7 +119892,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -119918,7 +119918,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -119944,7 +119944,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -119970,7 +119970,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -119996,7 +119996,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120022,7 +120022,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120048,7 +120048,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120074,7 +120074,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120100,7 +120100,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120126,7 +120126,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120152,7 +120152,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120178,7 +120178,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120204,7 +120204,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120230,7 +120230,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120256,7 +120256,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120282,7 +120282,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120308,7 +120308,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120334,7 +120334,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120360,7 +120360,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120386,7 +120386,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120412,7 +120412,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120438,7 +120438,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120464,7 +120464,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120490,7 +120490,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120516,7 +120516,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120542,7 +120542,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120568,7 +120568,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120594,7 +120594,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120620,7 +120620,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120646,7 +120646,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120672,7 +120672,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120698,7 +120698,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120724,7 +120724,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120750,7 +120750,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120776,7 +120776,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120802,7 +120802,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120828,7 +120828,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120854,7 +120854,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120880,7 +120880,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120906,7 +120906,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120932,7 +120932,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120958,7 +120958,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -120984,7 +120984,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -121010,7 +121010,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -121036,7 +121036,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -121062,7 +121062,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -121088,7 +121088,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -121156,7 +121156,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -121224,7 +121224,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -121292,7 +121292,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -121360,7 +121360,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -121428,7 +121428,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -121496,7 +121496,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -121605,7 +121605,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -121631,7 +121631,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -121657,7 +121657,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -121683,7 +121683,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -121709,7 +121709,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -121735,7 +121735,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -121761,7 +121761,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -121787,7 +121787,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -121813,7 +121813,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -121839,7 +121839,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -121865,7 +121865,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -121891,7 +121891,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -121917,7 +121917,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -121943,7 +121943,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -121969,7 +121969,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -121995,7 +121995,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122021,7 +122021,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122047,7 +122047,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122073,7 +122073,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122099,7 +122099,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122125,7 +122125,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122151,7 +122151,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122177,7 +122177,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122203,7 +122203,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122229,7 +122229,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122255,7 +122255,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122281,7 +122281,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122307,7 +122307,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122333,7 +122333,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122359,7 +122359,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122385,7 +122385,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122411,7 +122411,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122437,7 +122437,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122463,7 +122463,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122489,7 +122489,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122515,7 +122515,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122541,7 +122541,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122567,7 +122567,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122593,7 +122593,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122619,7 +122619,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122645,7 +122645,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122671,7 +122671,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122697,7 +122697,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122723,7 +122723,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122749,7 +122749,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122775,7 +122775,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122801,7 +122801,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122827,7 +122827,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122853,7 +122853,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122879,7 +122879,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122905,7 +122905,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122931,7 +122931,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122957,7 +122957,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -122983,7 +122983,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -123009,7 +123009,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -123035,7 +123035,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -123061,7 +123061,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -123087,7 +123087,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -123113,7 +123113,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -123139,7 +123139,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -123165,7 +123165,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -123233,7 +123233,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -123301,7 +123301,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -123369,7 +123369,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -123437,7 +123437,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -123505,7 +123505,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -123573,7 +123573,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -123682,7 +123682,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -123708,7 +123708,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -123734,7 +123734,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -123760,7 +123760,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -123786,7 +123786,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -123812,7 +123812,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -123838,7 +123838,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -123864,7 +123864,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -123890,7 +123890,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -123916,7 +123916,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -123942,7 +123942,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -123968,7 +123968,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -123994,7 +123994,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124020,7 +124020,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124046,7 +124046,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124072,7 +124072,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124098,7 +124098,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124124,7 +124124,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124150,7 +124150,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124176,7 +124176,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124202,7 +124202,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124228,7 +124228,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124254,7 +124254,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124280,7 +124280,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124306,7 +124306,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124332,7 +124332,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124358,7 +124358,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124384,7 +124384,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124410,7 +124410,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124436,7 +124436,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124462,7 +124462,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124488,7 +124488,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124514,7 +124514,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124540,7 +124540,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124566,7 +124566,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124592,7 +124592,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124618,7 +124618,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124644,7 +124644,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124670,7 +124670,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124696,7 +124696,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124722,7 +124722,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124748,7 +124748,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124774,7 +124774,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124800,7 +124800,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124826,7 +124826,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124852,7 +124852,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124878,7 +124878,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124904,7 +124904,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124930,7 +124930,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124956,7 +124956,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -124982,7 +124982,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -125008,7 +125008,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -125034,7 +125034,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -125060,7 +125060,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -125086,7 +125086,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -125112,7 +125112,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -125138,7 +125138,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -125164,7 +125164,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -125190,7 +125190,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -125216,7 +125216,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -125242,7 +125242,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -125310,7 +125310,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -125378,7 +125378,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -125446,7 +125446,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -125514,7 +125514,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -125582,7 +125582,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -125650,7 +125650,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -125759,7 +125759,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -125785,7 +125785,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -125811,7 +125811,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -125837,7 +125837,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -125863,7 +125863,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -125889,7 +125889,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -125915,7 +125915,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -125941,7 +125941,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -125967,7 +125967,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -125993,7 +125993,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126019,7 +126019,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126045,7 +126045,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126071,7 +126071,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126097,7 +126097,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126123,7 +126123,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126149,7 +126149,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126175,7 +126175,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126201,7 +126201,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126227,7 +126227,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126253,7 +126253,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126279,7 +126279,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126305,7 +126305,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126331,7 +126331,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126357,7 +126357,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126383,7 +126383,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126409,7 +126409,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126435,7 +126435,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126461,7 +126461,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126487,7 +126487,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126513,7 +126513,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126539,7 +126539,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126565,7 +126565,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126591,7 +126591,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126617,7 +126617,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126643,7 +126643,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126669,7 +126669,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126695,7 +126695,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126721,7 +126721,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126747,7 +126747,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126773,7 +126773,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126799,7 +126799,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126825,7 +126825,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126851,7 +126851,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126877,7 +126877,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126903,7 +126903,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126929,7 +126929,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126955,7 +126955,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -126981,7 +126981,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -127007,7 +127007,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -127033,7 +127033,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -127059,7 +127059,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -127085,7 +127085,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -127111,7 +127111,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -127137,7 +127137,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -127163,7 +127163,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -127189,7 +127189,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -127215,7 +127215,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -127241,7 +127241,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -127267,7 +127267,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -127293,7 +127293,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -127319,7 +127319,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -127387,7 +127387,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -127455,7 +127455,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -127523,7 +127523,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -127591,7 +127591,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -127659,7 +127659,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -127727,7 +127727,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -127842,7 +127842,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -127868,7 +127868,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -127894,7 +127894,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -127920,7 +127920,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -127946,7 +127946,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -127972,7 +127972,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -127998,7 +127998,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -128024,7 +128024,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -128100,7 +128100,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -128126,7 +128126,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -128152,7 +128152,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -128178,7 +128178,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -128204,7 +128204,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -128230,7 +128230,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -128256,7 +128256,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -128282,7 +128282,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -128388,7 +128388,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -128414,7 +128414,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -128523,7 +128523,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -128549,7 +128549,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -128688,7 +128688,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -128714,7 +128714,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -128823,7 +128823,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -128849,7 +128849,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -128958,7 +128958,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -128984,7 +128984,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -129093,7 +129093,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -129119,7 +129119,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -129228,7 +129228,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -129254,7 +129254,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -129363,7 +129363,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 17.5, "volume": 12.5, "wellLocation": { "offset": { @@ -129389,7 +129389,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 4.0, + "flowRate": 28.5, "volume": 12.5, "wellLocation": { "offset": { @@ -129552,7 +129552,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -129578,7 +129578,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -129604,7 +129604,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -129630,7 +129630,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -129656,7 +129656,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -129682,7 +129682,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -129708,7 +129708,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -129734,7 +129734,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -129760,7 +129760,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -129786,7 +129786,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -129812,7 +129812,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -129838,7 +129838,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -129864,7 +129864,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -129890,7 +129890,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -129916,7 +129916,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -129942,7 +129942,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -129968,7 +129968,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -129994,7 +129994,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130020,7 +130020,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130046,7 +130046,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130072,7 +130072,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130098,7 +130098,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130124,7 +130124,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130150,7 +130150,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130176,7 +130176,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130202,7 +130202,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130228,7 +130228,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130254,7 +130254,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130280,7 +130280,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130306,7 +130306,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130332,7 +130332,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130358,7 +130358,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130384,7 +130384,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130410,7 +130410,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130436,7 +130436,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130462,7 +130462,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130488,7 +130488,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130514,7 +130514,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130540,7 +130540,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130566,7 +130566,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130592,7 +130592,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130618,7 +130618,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130644,7 +130644,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130670,7 +130670,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130696,7 +130696,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130722,7 +130722,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130748,7 +130748,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130774,7 +130774,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130800,7 +130800,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130826,7 +130826,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130852,7 +130852,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130878,7 +130878,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130904,7 +130904,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130930,7 +130930,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130956,7 +130956,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -130982,7 +130982,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -131008,7 +131008,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -131034,7 +131034,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -131060,7 +131060,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -131086,7 +131086,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -131112,7 +131112,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -131180,7 +131180,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -131248,7 +131248,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -131316,7 +131316,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -131384,7 +131384,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -131452,7 +131452,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -131520,7 +131520,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -131629,7 +131629,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -131655,7 +131655,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -131681,7 +131681,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -131707,7 +131707,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -131733,7 +131733,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -131759,7 +131759,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -131785,7 +131785,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -131811,7 +131811,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -131837,7 +131837,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -131863,7 +131863,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -131889,7 +131889,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -131915,7 +131915,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -131941,7 +131941,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -131967,7 +131967,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -131993,7 +131993,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132019,7 +132019,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132045,7 +132045,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132071,7 +132071,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132097,7 +132097,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132123,7 +132123,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132149,7 +132149,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132175,7 +132175,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132201,7 +132201,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132227,7 +132227,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132253,7 +132253,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132279,7 +132279,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132305,7 +132305,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132331,7 +132331,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132357,7 +132357,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132383,7 +132383,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132409,7 +132409,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132435,7 +132435,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132461,7 +132461,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132487,7 +132487,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132513,7 +132513,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132539,7 +132539,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132565,7 +132565,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132591,7 +132591,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132617,7 +132617,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132643,7 +132643,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132669,7 +132669,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132695,7 +132695,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132721,7 +132721,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132747,7 +132747,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132773,7 +132773,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132799,7 +132799,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132825,7 +132825,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132851,7 +132851,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132877,7 +132877,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132903,7 +132903,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132929,7 +132929,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132955,7 +132955,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -132981,7 +132981,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -133007,7 +133007,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -133033,7 +133033,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -133059,7 +133059,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -133085,7 +133085,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -133111,7 +133111,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -133137,7 +133137,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -133163,7 +133163,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -133189,7 +133189,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -133257,7 +133257,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -133325,7 +133325,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -133393,7 +133393,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -133461,7 +133461,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -133529,7 +133529,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -133597,7 +133597,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -133706,7 +133706,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -133732,7 +133732,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -133758,7 +133758,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -133784,7 +133784,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -133810,7 +133810,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -133836,7 +133836,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -133862,7 +133862,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -133888,7 +133888,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -133914,7 +133914,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -133940,7 +133940,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -133966,7 +133966,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -133992,7 +133992,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134018,7 +134018,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134044,7 +134044,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134070,7 +134070,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134096,7 +134096,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134122,7 +134122,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134148,7 +134148,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134174,7 +134174,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134200,7 +134200,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134226,7 +134226,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134252,7 +134252,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134278,7 +134278,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134304,7 +134304,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134330,7 +134330,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134356,7 +134356,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134382,7 +134382,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134408,7 +134408,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134434,7 +134434,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134460,7 +134460,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134486,7 +134486,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134512,7 +134512,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134538,7 +134538,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134564,7 +134564,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134590,7 +134590,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134616,7 +134616,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134642,7 +134642,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134668,7 +134668,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134694,7 +134694,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134720,7 +134720,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134746,7 +134746,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134772,7 +134772,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134798,7 +134798,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134824,7 +134824,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134850,7 +134850,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134876,7 +134876,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134902,7 +134902,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134928,7 +134928,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134954,7 +134954,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -134980,7 +134980,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -135006,7 +135006,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -135032,7 +135032,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -135058,7 +135058,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -135084,7 +135084,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -135110,7 +135110,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -135136,7 +135136,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -135162,7 +135162,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -135188,7 +135188,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -135214,7 +135214,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -135240,7 +135240,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -135266,7 +135266,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -135334,7 +135334,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -135402,7 +135402,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -135470,7 +135470,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -135538,7 +135538,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -135606,7 +135606,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -135674,7 +135674,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -135783,7 +135783,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -135809,7 +135809,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -135835,7 +135835,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -135861,7 +135861,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -135887,7 +135887,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -135913,7 +135913,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -135939,7 +135939,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -135965,7 +135965,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -135991,7 +135991,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136017,7 +136017,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136043,7 +136043,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136069,7 +136069,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136095,7 +136095,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136121,7 +136121,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136147,7 +136147,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136173,7 +136173,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136199,7 +136199,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136225,7 +136225,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136251,7 +136251,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136277,7 +136277,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136303,7 +136303,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136329,7 +136329,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136355,7 +136355,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136381,7 +136381,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136407,7 +136407,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136433,7 +136433,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136459,7 +136459,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136485,7 +136485,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136511,7 +136511,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136537,7 +136537,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136563,7 +136563,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136589,7 +136589,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136615,7 +136615,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136641,7 +136641,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136667,7 +136667,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136693,7 +136693,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136719,7 +136719,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136745,7 +136745,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136771,7 +136771,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136797,7 +136797,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136823,7 +136823,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136849,7 +136849,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136875,7 +136875,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136901,7 +136901,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136927,7 +136927,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136953,7 +136953,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -136979,7 +136979,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -137005,7 +137005,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -137031,7 +137031,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -137057,7 +137057,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -137083,7 +137083,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -137109,7 +137109,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -137135,7 +137135,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -137161,7 +137161,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -137187,7 +137187,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -137213,7 +137213,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -137239,7 +137239,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -137265,7 +137265,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -137291,7 +137291,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -137317,7 +137317,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -137343,7 +137343,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -137411,7 +137411,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -137479,7 +137479,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -137547,7 +137547,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -137615,7 +137615,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -137683,7 +137683,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -137751,7 +137751,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -137860,7 +137860,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -137886,7 +137886,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -137912,7 +137912,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -137938,7 +137938,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -137964,7 +137964,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -137990,7 +137990,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138016,7 +138016,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138042,7 +138042,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138068,7 +138068,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138094,7 +138094,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138120,7 +138120,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138146,7 +138146,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138172,7 +138172,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138198,7 +138198,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138224,7 +138224,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138250,7 +138250,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138276,7 +138276,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138302,7 +138302,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138328,7 +138328,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138354,7 +138354,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138380,7 +138380,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138406,7 +138406,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138432,7 +138432,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138458,7 +138458,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138484,7 +138484,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138510,7 +138510,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138536,7 +138536,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138562,7 +138562,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138588,7 +138588,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138614,7 +138614,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138640,7 +138640,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138666,7 +138666,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138692,7 +138692,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138718,7 +138718,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138744,7 +138744,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138770,7 +138770,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138796,7 +138796,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138822,7 +138822,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138848,7 +138848,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138874,7 +138874,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138900,7 +138900,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138926,7 +138926,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138952,7 +138952,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -138978,7 +138978,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -139004,7 +139004,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -139030,7 +139030,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -139056,7 +139056,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -139082,7 +139082,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -139108,7 +139108,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -139134,7 +139134,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -139160,7 +139160,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -139186,7 +139186,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -139212,7 +139212,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -139238,7 +139238,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -139264,7 +139264,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -139290,7 +139290,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -139316,7 +139316,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -139342,7 +139342,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -139368,7 +139368,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -139394,7 +139394,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -139420,7 +139420,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -139488,7 +139488,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -139556,7 +139556,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -139624,7 +139624,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -139692,7 +139692,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -139760,7 +139760,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -139828,7 +139828,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -139937,7 +139937,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -139963,7 +139963,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -139989,7 +139989,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140015,7 +140015,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140041,7 +140041,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140067,7 +140067,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140093,7 +140093,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140119,7 +140119,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140145,7 +140145,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140171,7 +140171,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140197,7 +140197,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140223,7 +140223,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140249,7 +140249,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140275,7 +140275,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140301,7 +140301,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140327,7 +140327,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140353,7 +140353,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140379,7 +140379,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140405,7 +140405,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140431,7 +140431,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140457,7 +140457,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140483,7 +140483,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140509,7 +140509,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140535,7 +140535,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140561,7 +140561,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140587,7 +140587,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140613,7 +140613,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140639,7 +140639,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140665,7 +140665,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140691,7 +140691,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140717,7 +140717,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140743,7 +140743,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140769,7 +140769,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140795,7 +140795,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140821,7 +140821,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140847,7 +140847,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140873,7 +140873,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140899,7 +140899,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140925,7 +140925,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140951,7 +140951,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -140977,7 +140977,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -141003,7 +141003,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -141029,7 +141029,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -141055,7 +141055,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -141081,7 +141081,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -141107,7 +141107,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -141133,7 +141133,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -141159,7 +141159,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -141185,7 +141185,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -141211,7 +141211,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -141237,7 +141237,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -141263,7 +141263,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -141289,7 +141289,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -141315,7 +141315,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -141341,7 +141341,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -141367,7 +141367,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -141393,7 +141393,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -141419,7 +141419,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -141445,7 +141445,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -141471,7 +141471,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -141497,7 +141497,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -141565,7 +141565,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -141633,7 +141633,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -141701,7 +141701,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -141769,7 +141769,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -141837,7 +141837,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -141905,7 +141905,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -142014,7 +142014,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142040,7 +142040,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142066,7 +142066,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142092,7 +142092,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142118,7 +142118,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142144,7 +142144,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142170,7 +142170,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142196,7 +142196,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142222,7 +142222,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142248,7 +142248,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142274,7 +142274,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142300,7 +142300,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142326,7 +142326,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142352,7 +142352,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142378,7 +142378,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142404,7 +142404,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142430,7 +142430,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142456,7 +142456,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142482,7 +142482,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142508,7 +142508,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142534,7 +142534,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142560,7 +142560,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142586,7 +142586,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142612,7 +142612,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142638,7 +142638,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142664,7 +142664,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142690,7 +142690,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142716,7 +142716,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142742,7 +142742,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142768,7 +142768,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142794,7 +142794,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142820,7 +142820,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142846,7 +142846,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142872,7 +142872,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142898,7 +142898,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142924,7 +142924,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142950,7 +142950,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -142976,7 +142976,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143002,7 +143002,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143028,7 +143028,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143054,7 +143054,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143080,7 +143080,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143106,7 +143106,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143132,7 +143132,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143158,7 +143158,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143184,7 +143184,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143210,7 +143210,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143236,7 +143236,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143262,7 +143262,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143288,7 +143288,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143314,7 +143314,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143340,7 +143340,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143366,7 +143366,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143392,7 +143392,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143418,7 +143418,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143444,7 +143444,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143470,7 +143470,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143496,7 +143496,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143522,7 +143522,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143548,7 +143548,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -143574,7 +143574,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -143642,7 +143642,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -143710,7 +143710,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -143778,7 +143778,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -143846,7 +143846,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -143914,7 +143914,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -143982,7 +143982,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -144091,7 +144091,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144117,7 +144117,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144143,7 +144143,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144169,7 +144169,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144195,7 +144195,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144221,7 +144221,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144247,7 +144247,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144273,7 +144273,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144299,7 +144299,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144325,7 +144325,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144351,7 +144351,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144377,7 +144377,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144403,7 +144403,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144429,7 +144429,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144455,7 +144455,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144481,7 +144481,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144507,7 +144507,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144533,7 +144533,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144559,7 +144559,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144585,7 +144585,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144611,7 +144611,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144637,7 +144637,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144663,7 +144663,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144689,7 +144689,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144715,7 +144715,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144741,7 +144741,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144767,7 +144767,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144793,7 +144793,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144819,7 +144819,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144845,7 +144845,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144871,7 +144871,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144897,7 +144897,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144923,7 +144923,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144949,7 +144949,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -144975,7 +144975,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145001,7 +145001,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145027,7 +145027,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145053,7 +145053,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145079,7 +145079,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145105,7 +145105,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145131,7 +145131,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145157,7 +145157,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145183,7 +145183,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145209,7 +145209,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145235,7 +145235,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145261,7 +145261,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145287,7 +145287,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145313,7 +145313,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145339,7 +145339,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145365,7 +145365,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145391,7 +145391,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145417,7 +145417,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145443,7 +145443,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145469,7 +145469,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145495,7 +145495,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145521,7 +145521,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145547,7 +145547,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145573,7 +145573,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145599,7 +145599,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145625,7 +145625,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -145651,7 +145651,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 62.0, "wellLocation": { "offset": { @@ -145719,7 +145719,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -145787,7 +145787,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -145855,7 +145855,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -145923,7 +145923,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -145991,7 +145991,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -146059,7 +146059,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 10.0, "wellLocation": { "offset": { @@ -146125,7 +146125,7 @@ "errors": [], "files": [ { - "name": "Flex_P50MLeft_P1000MRight_None_2_15_ABRKAPALibraryQuantLongv2.py", + "name": "Flex_S_v2_15_P50M_P1000M_KAPALibraryQuantLongv2.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[89a255db0b][OT2_X_v2_18_None_None_StrRTPwith_unit].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[89a255db0b][OT2_X_v2_18_None_None_StrRTPwith_unit].json new file mode 100644 index 00000000000..7dd2a932a28 --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[89a255db0b][OT2_X_v2_18_None_None_StrRTPwith_unit].json @@ -0,0 +1,74 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + } + ], + "config": { + "apiVersion": [ + 2, + 18 + ], + "protocolType": "python" + }, + "errors": [ + { + "detail": "TypeError [line 11]: ParameterContext.add_str() got an unexpected keyword argument 'unit'", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ExceptionInProtocolError", + "wrappedErrors": [ + { + "detail": "TypeError: ParameterContext.add_str() got an unexpected keyword argument 'unit'", + "errorCode": "4000", + "errorInfo": { + "args": "(\"ParameterContext.add_str() got an unexpected keyword argument 'unit'\",)", + "class": "TypeError", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 80, in _parse_and_set_parameters\n exec(\"add_parameters(__param_context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"OT2_X_v2_18_None_None_StrRTPwith_unit.py\", line 11, in add_parameters\n" + }, + "errorType": "PythonException", + "wrappedErrors": [] + } + ] + } + ], + "files": [ + { + "name": "OT2_X_v2_18_None_None_StrRTPwith_unit.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "protocolName": "Str RTP with unit" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-2 Standard", + "runTimeParameters": [] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[13efc9bfcd][Flex_P1000_96_TC_2_16_AnalysisError_PartialTipPickupThermocyclerLidConflict].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[89a8226c4e][Flex_X_v2_16_P1000_96_TC_PartialTipPickupThermocyclerLidConflict].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[13efc9bfcd][Flex_P1000_96_TC_2_16_AnalysisError_PartialTipPickupThermocyclerLidConflict].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[89a8226c4e][Flex_X_v2_16_P1000_96_TC_PartialTipPickupThermocyclerLidConflict].json index 89bbec0231b..942e6e97b53 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[13efc9bfcd][Flex_P1000_96_TC_2_16_AnalysisError_PartialTipPickupThermocyclerLidConflict].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[89a8226c4e][Flex_X_v2_16_P1000_96_TC_PartialTipPickupThermocyclerLidConflict].json @@ -2,12 +2,14 @@ "commands": [ { "commandType": "home", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "loadLabware", + "notes": [], "params": { "loadName": "opentrons_flex_96_tiprack_50ul", "location": { @@ -1159,6 +1161,7 @@ }, { "commandType": "loadPipette", + "notes": [], "params": { "mount": "left", "pipetteName": "p1000_96" @@ -1168,6 +1171,7 @@ }, { "commandType": "loadLabware", + "notes": [], "params": { "loadName": "nest_96_wellplate_200ul_flat", "location": { @@ -2328,6 +2332,7 @@ }, { "commandType": "loadLabware", + "notes": [], "params": { "loadName": "nest_96_wellplate_200ul_flat", "location": { @@ -3488,6 +3493,7 @@ }, { "commandType": "loadModule", + "notes": [], "params": { "location": { "slotName": "B1" @@ -3596,6 +3602,7 @@ }, { "commandType": "loadLabware", + "notes": [], "params": { "loadName": "nest_96_wellplate_200ul_flat", "location": { @@ -4756,6 +4763,7 @@ }, { "commandType": "configureNozzleLayout", + "notes": [], "params": { "configurationParams": { "primaryNozzle": "A12", @@ -4767,6 +4775,7 @@ }, { "commandType": "pickUpTip", + "notes": [], "params": { "wellLocation": { "offset": { @@ -4792,6 +4801,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 50.0, @@ -4817,6 +4827,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "volume": 20.0, @@ -4867,7 +4878,7 @@ ], "files": [ { - "name": "Flex_P1000_96_TC_2_16_AnalysisError_PartialTipPickupThermocyclerLidConflict.py", + "name": "Flex_X_v2_16_P1000_96_TC_PartialTipPickupThermocyclerLidConflict.py", "role": "main" }, { @@ -4937,5 +4948,6 @@ "pipetteName": "p1000_96" } ], - "robotType": "OT-3 Standard" + "robotType": "OT-3 Standard", + "runTimeParameters": [] } diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[8df082e960][OT2_P300MLeft_MM_TM_2_4_Zymo].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[8df082e960][OT2_P300MLeft_MM_TM_2_4_Zymo].json deleted file mode 100644 index a2af41a1a02..00000000000 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[8df082e960][OT2_P300MLeft_MM_TM_2_4_Zymo].json +++ /dev/null @@ -1,11068 +0,0 @@ -{ - "commands": [ - { - "commandType": "home", - "notes": [], - "params": {}, - "result": {}, - "status": "succeeded" - }, - { - "commandType": "loadModule", - "notes": [], - "params": { - "location": { - "slotName": "6" - }, - "model": "magneticModuleV2" - }, - "result": { - "definition": { - "calibrationPoint": { - "x": 124.875, - "y": 2.75, - "z": 82.25 - }, - "compatibleWith": [], - "dimensions": { - "bareOverallHeight": 110.152, - "overLabwareHeight": 4.052 - }, - "displayName": "Magnetic Module GEN2", - "gripperOffsets": {}, - "labwareOffset": { - "x": -1.175, - "y": -0.125, - "z": 82.25 - }, - "model": "magneticModuleV2", - "moduleType": "magneticModuleType", - "otSharedSchema": "module/schemas/2", - "quirks": [], - "slotTransforms": { - "ot2_short_trash": { - "3": { - "labwareOffset": [ - [ - -1, - 0, - 0, - 0.3 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - }, - "6": { - "labwareOffset": [ - [ - -1, - 0, - 0, - 0.3 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - }, - "9": { - "labwareOffset": [ - [ - -1, - 0, - 0, - 0.3 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - } - }, - "ot2_standard": { - "3": { - "labwareOffset": [ - [ - -1, - 0, - 0, - 0.25 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - }, - "6": { - "labwareOffset": [ - [ - -1, - 0, - 0, - 0.25 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - }, - "9": { - "labwareOffset": [ - [ - -1, - 0, - 0, - 0.25 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - } - } - } - }, - "model": "magneticModuleV2" - }, - "status": "succeeded" - }, - { - "commandType": "custom", - "notes": [], - "params": { - "legacyCommandText": "Disengaging Magnetic Module", - "legacyCommandType": "command.MAGDECK_DISENGAGE" - }, - "result": {}, - "status": "succeeded" - }, - { - "commandType": "loadLabware", - "notes": [], - "params": { - "displayName": "deepwell plate", - "loadName": "nest_96_wellplate_2ml_deep", - "location": {}, - "namespace": "opentrons", - "version": 1 - }, - "result": { - "definition": { - "allowedRoles": [], - "brand": { - "brand": "NEST", - "brandId": [ - "503001", - "503501" - ], - "links": [ - "https://www.nest-biotech.com/deep-well-plates/59253726.html" - ] - }, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - }, - "dimensions": { - "xDimension": 127.6, - "yDimension": 85.3, - "zDimension": 41 - }, - "gripperOffsets": {}, - "groups": [ - { - "brand": { - "brand": "NEST", - "brandId": [] - }, - "metadata": { - "displayCategory": "wellPlate", - "displayName": "NEST 96 Deep Well Plate 2mL", - "wellBottomShape": "v" - }, - "wells": [ - "A1", - "A10", - "A11", - "A12", - "A2", - "A3", - "A4", - "A5", - "A6", - "A7", - "A8", - "A9", - "B1", - "B10", - "B11", - "B12", - "B2", - "B3", - "B4", - "B5", - "B6", - "B7", - "B8", - "B9", - "C1", - "C10", - "C11", - "C12", - "C2", - "C3", - "C4", - "C5", - "C6", - "C7", - "C8", - "C9", - "D1", - "D10", - "D11", - "D12", - "D2", - "D3", - "D4", - "D5", - "D6", - "D7", - "D8", - "D9", - "E1", - "E10", - "E11", - "E12", - "E2", - "E3", - "E4", - "E5", - "E6", - "E7", - "E8", - "E9", - "F1", - "F10", - "F11", - "F12", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - "F8", - "F9", - "G1", - "G10", - "G11", - "G12", - "G2", - "G3", - "G4", - "G5", - "G6", - "G7", - "G8", - "G9", - "H1", - "H10", - "H11", - "H12", - "H2", - "H3", - "H4", - "H5", - "H6", - "H7", - "H8", - "H9" - ] - } - ], - "metadata": { - "displayCategory": "wellPlate", - "displayName": "NEST 96 Deep Well Plate 2mL", - "displayVolumeUnits": "µL", - "tags": [] - }, - "namespace": "opentrons", - "ordering": [ - [ - "A1", - "B1", - "C1", - "D1", - "E1", - "F1", - "G1", - "H1" - ], - [ - "A10", - "B10", - "C10", - "D10", - "E10", - "F10", - "G10", - "H10" - ], - [ - "A11", - "B11", - "C11", - "D11", - "E11", - "F11", - "G11", - "H11" - ], - [ - "A12", - "B12", - "C12", - "D12", - "E12", - "F12", - "G12", - "H12" - ], - [ - "A2", - "B2", - "C2", - "D2", - "E2", - "F2", - "G2", - "H2" - ], - [ - "A3", - "B3", - "C3", - "D3", - "E3", - "F3", - "G3", - "H3" - ], - [ - "A4", - "B4", - "C4", - "D4", - "E4", - "F4", - "G4", - "H4" - ], - [ - "A5", - "B5", - "C5", - "D5", - "E5", - "F5", - "G5", - "H5" - ], - [ - "A6", - "B6", - "C6", - "D6", - "E6", - "F6", - "G6", - "H6" - ], - [ - "A7", - "B7", - "C7", - "D7", - "E7", - "F7", - "G7", - "H7" - ], - [ - "A8", - "B8", - "C8", - "D8", - "E8", - "F8", - "G8", - "H8" - ], - [ - "A9", - "B9", - "C9", - "D9", - "E9", - "F9", - "G9", - "H9" - ] - ], - "parameters": { - "format": "96Standard", - "isMagneticModuleCompatible": true, - "isTiprack": false, - "loadName": "nest_96_wellplate_2ml_deep", - "magneticModuleEngageHeight": 6.8, - "quirks": [] - }, - "schemaVersion": 2, - "stackingOffsetWithLabware": {}, - "stackingOffsetWithModule": {}, - "version": 1, - "wells": { - "A1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "A10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "A11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "A12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "A2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "A3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "A4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "A5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "A6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "A7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "A8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "A9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 74.15, - "yDimension": 8.2, - "z": 3 - }, - "B1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "B10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "B11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "B12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "B2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "B3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "B4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "B5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "B6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "B7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "B8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "B9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 65.15, - "yDimension": 8.2, - "z": 3 - }, - "C1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "C10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "C11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "C12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "C2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "C3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "C4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "C5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "C6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "C7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "C8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "C9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 56.15, - "yDimension": 8.2, - "z": 3 - }, - "D1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "D10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "D11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "D12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "D2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "D3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "D4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "D5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "D6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "D7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "D8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "D9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 47.15, - "yDimension": 8.2, - "z": 3 - }, - "E1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "E10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "E11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "E12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "E2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "E3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "E4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "E5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "E6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "E7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "E8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "E9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 38.15, - "yDimension": 8.2, - "z": 3 - }, - "F1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "F10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "F11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "F12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "F2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "F3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "F4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "F5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "F6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "F7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "F8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "F9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 29.15, - "yDimension": 8.2, - "z": 3 - }, - "G1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "G10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "G11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "G12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "G2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "G3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "G4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "G5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "G6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "G7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "G8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "G9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 20.15, - "yDimension": 8.2, - "z": 3 - }, - "H1": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 14.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - }, - "H10": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 95.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - }, - "H11": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 104.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - }, - "H12": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 113.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - }, - "H2": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 23.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - }, - "H3": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 32.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - }, - "H4": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 41.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - }, - "H5": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 50.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - }, - "H6": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 59.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - }, - "H7": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 68.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - }, - "H8": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 77.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - }, - "H9": { - "depth": 38, - "shape": "rectangular", - "totalLiquidVolume": 2000, - "x": 86.3, - "xDimension": 8.2, - "y": 11.15, - "yDimension": 8.2, - "z": 3 - } - } - } - }, - "status": "succeeded" - }, - { - "commandType": "loadModule", - "notes": [], - "params": { - "location": { - "slotName": "1" - }, - "model": "temperatureModuleV2" - }, - "result": { - "definition": { - "calibrationPoint": { - "x": 11.7, - "y": 8.75, - "z": 80.09 - }, - "compatibleWith": [ - "temperatureModuleV1" - ], - "dimensions": { - "bareOverallHeight": 84.0, - "overLabwareHeight": 0.0 - }, - "displayName": "Temperature Module GEN2", - "gripperOffsets": { - "default": { - "dropOffset": { - "x": 0.0, - "y": 0.0, - "z": 1.0 - }, - "pickUpOffset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - } - } - }, - "labwareOffset": { - "x": -1.45, - "y": -0.15, - "z": 80.09 - }, - "model": "temperatureModuleV2", - "moduleType": "temperatureModuleType", - "otSharedSchema": "module/schemas/2", - "quirks": [], - "slotTransforms": { - "ot2_short_trash": { - "3": { - "labwareOffset": [ - [ - -1, - -0.15, - 0, - 0 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - }, - "6": { - "labwareOffset": [ - [ - -1, - -0.15, - 0, - 0 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - }, - "9": { - "labwareOffset": [ - [ - -1, - -0.15, - 0, - 0 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - } - }, - "ot2_standard": { - "3": { - "labwareOffset": [ - [ - -1, - -0.3, - 0, - 0 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - }, - "6": { - "labwareOffset": [ - [ - -1, - -0.3, - 0, - 0 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - }, - "9": { - "labwareOffset": [ - [ - -1, - -0.3, - 0, - 0 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ] - ] - } - }, - "ot3_standard": { - "A1": { - "labwareOffset": [ - [ - -71.09, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.15, - 1 - ], - [ - 0, - 0, - 1, - 1.45 - ] - ] - }, - "A3": { - "labwareOffset": [ - [ - -71.09, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.15, - 1 - ], - [ - 0, - 0, - 1, - 1.45 - ] - ] - }, - "B1": { - "labwareOffset": [ - [ - -71.09, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.15, - 1 - ], - [ - 0, - 0, - 1, - 1.45 - ] - ] - }, - "B3": { - "labwareOffset": [ - [ - -71.09, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.15, - 1 - ], - [ - 0, - 0, - 1, - 1.45 - ] - ] - }, - "C1": { - "labwareOffset": [ - [ - -71.09, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.15, - 1 - ], - [ - 0, - 0, - 1, - 1.45 - ] - ] - }, - "C3": { - "labwareOffset": [ - [ - -71.09, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.15, - 1 - ], - [ - 0, - 0, - 1, - 1.45 - ] - ] - }, - "D1": { - "labwareOffset": [ - [ - -71.09, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.15, - 1 - ], - [ - 0, - 0, - 1, - 1.45 - ] - ] - }, - "D3": { - "labwareOffset": [ - [ - -71.09, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0, - 1 - ], - [ - 0, - 0, - 0.15, - 1 - ], - [ - 0, - 0, - 1, - 1.45 - ] - ] - } - } - } - }, - "model": "temperatureModuleV2" - }, - "status": "succeeded" - }, - { - "commandType": "loadLabware", - "notes": [], - "params": { - "loadName": "opentrons_96_aluminumblock_nest_wellplate_100ul", - "location": {}, - "namespace": "opentrons", - "version": 1 - }, - "result": { - "definition": { - "allowedRoles": [], - "brand": { - "brand": "Opentrons", - "brandId": [], - "links": [ - "https://shop.opentrons.com/collections/hardware-modules/products/aluminum-block-set" - ] - }, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - }, - "dimensions": { - "xDimension": 127.75, - "yDimension": 85.45, - "zDimension": 21.2 - }, - "gripperOffsets": {}, - "groups": [ - { - "brand": { - "brand": "NEST", - "brandId": [ - "402501" - ], - "links": [ - "https://www.nest-biotech.com/pcr-plates/58773587.html" - ] - }, - "metadata": { - "displayCategory": "wellPlate", - "displayName": "NEST 96 Well Plate 100 µL", - "wellBottomShape": "v" - }, - "wells": [ - "A1", - "A10", - "A11", - "A12", - "A2", - "A3", - "A4", - "A5", - "A6", - "A7", - "A8", - "A9", - "B1", - "B10", - "B11", - "B12", - "B2", - "B3", - "B4", - "B5", - "B6", - "B7", - "B8", - "B9", - "C1", - "C10", - "C11", - "C12", - "C2", - "C3", - "C4", - "C5", - "C6", - "C7", - "C8", - "C9", - "D1", - "D10", - "D11", - "D12", - "D2", - "D3", - "D4", - "D5", - "D6", - "D7", - "D8", - "D9", - "E1", - "E10", - "E11", - "E12", - "E2", - "E3", - "E4", - "E5", - "E6", - "E7", - "E8", - "E9", - "F1", - "F10", - "F11", - "F12", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - "F8", - "F9", - "G1", - "G10", - "G11", - "G12", - "G2", - "G3", - "G4", - "G5", - "G6", - "G7", - "G8", - "G9", - "H1", - "H10", - "H11", - "H12", - "H2", - "H3", - "H4", - "H5", - "H6", - "H7", - "H8", - "H9" - ] - } - ], - "metadata": { - "displayCategory": "aluminumBlock", - "displayName": "Opentrons 96 Well Aluminum Block with NEST Well Plate 100 µL", - "displayVolumeUnits": "µL", - "tags": [] - }, - "namespace": "opentrons", - "ordering": [ - [ - "A1", - "B1", - "C1", - "D1", - "E1", - "F1", - "G1", - "H1" - ], - [ - "A10", - "B10", - "C10", - "D10", - "E10", - "F10", - "G10", - "H10" - ], - [ - "A11", - "B11", - "C11", - "D11", - "E11", - "F11", - "G11", - "H11" - ], - [ - "A12", - "B12", - "C12", - "D12", - "E12", - "F12", - "G12", - "H12" - ], - [ - "A2", - "B2", - "C2", - "D2", - "E2", - "F2", - "G2", - "H2" - ], - [ - "A3", - "B3", - "C3", - "D3", - "E3", - "F3", - "G3", - "H3" - ], - [ - "A4", - "B4", - "C4", - "D4", - "E4", - "F4", - "G4", - "H4" - ], - [ - "A5", - "B5", - "C5", - "D5", - "E5", - "F5", - "G5", - "H5" - ], - [ - "A6", - "B6", - "C6", - "D6", - "E6", - "F6", - "G6", - "H6" - ], - [ - "A7", - "B7", - "C7", - "D7", - "E7", - "F7", - "G7", - "H7" - ], - [ - "A8", - "B8", - "C8", - "D8", - "E8", - "F8", - "G8", - "H8" - ], - [ - "A9", - "B9", - "C9", - "D9", - "E9", - "F9", - "G9", - "H9" - ] - ], - "parameters": { - "format": "96Standard", - "isMagneticModuleCompatible": false, - "isTiprack": false, - "loadName": "opentrons_96_aluminumblock_nest_wellplate_100ul", - "quirks": [ - "gripperIncompatible" - ] - }, - "schemaVersion": 2, - "stackingOffsetWithLabware": {}, - "stackingOffsetWithModule": {}, - "version": 1, - "wells": { - "A1": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 14.38, - "y": 74.2, - "z": 6.42 - }, - "A10": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 95.38, - "y": 74.2, - "z": 6.42 - }, - "A11": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 104.38, - "y": 74.2, - "z": 6.42 - }, - "A12": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 113.38, - "y": 74.2, - "z": 6.42 - }, - "A2": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 23.38, - "y": 74.2, - "z": 6.42 - }, - "A3": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 32.38, - "y": 74.2, - "z": 6.42 - }, - "A4": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 41.38, - "y": 74.2, - "z": 6.42 - }, - "A5": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 50.38, - "y": 74.2, - "z": 6.42 - }, - "A6": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 59.38, - "y": 74.2, - "z": 6.42 - }, - "A7": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 68.38, - "y": 74.2, - "z": 6.42 - }, - "A8": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 77.38, - "y": 74.2, - "z": 6.42 - }, - "A9": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 86.38, - "y": 74.2, - "z": 6.42 - }, - "B1": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 14.38, - "y": 65.2, - "z": 6.42 - }, - "B10": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 95.38, - "y": 65.2, - "z": 6.42 - }, - "B11": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 104.38, - "y": 65.2, - "z": 6.42 - }, - "B12": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 113.38, - "y": 65.2, - "z": 6.42 - }, - "B2": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 23.38, - "y": 65.2, - "z": 6.42 - }, - "B3": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 32.38, - "y": 65.2, - "z": 6.42 - }, - "B4": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 41.38, - "y": 65.2, - "z": 6.42 - }, - "B5": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 50.38, - "y": 65.2, - "z": 6.42 - }, - "B6": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 59.38, - "y": 65.2, - "z": 6.42 - }, - "B7": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 68.38, - "y": 65.2, - "z": 6.42 - }, - "B8": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 77.38, - "y": 65.2, - "z": 6.42 - }, - "B9": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 86.38, - "y": 65.2, - "z": 6.42 - }, - "C1": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 14.38, - "y": 56.2, - "z": 6.42 - }, - "C10": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 95.38, - "y": 56.2, - "z": 6.42 - }, - "C11": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 104.38, - "y": 56.2, - "z": 6.42 - }, - "C12": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 113.38, - "y": 56.2, - "z": 6.42 - }, - "C2": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 23.38, - "y": 56.2, - "z": 6.42 - }, - "C3": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 32.38, - "y": 56.2, - "z": 6.42 - }, - "C4": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 41.38, - "y": 56.2, - "z": 6.42 - }, - "C5": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 50.38, - "y": 56.2, - "z": 6.42 - }, - "C6": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 59.38, - "y": 56.2, - "z": 6.42 - }, - "C7": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 68.38, - "y": 56.2, - "z": 6.42 - }, - "C8": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 77.38, - "y": 56.2, - "z": 6.42 - }, - "C9": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 86.38, - "y": 56.2, - "z": 6.42 - }, - "D1": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 14.38, - "y": 47.2, - "z": 6.42 - }, - "D10": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 95.38, - "y": 47.2, - "z": 6.42 - }, - "D11": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 104.38, - "y": 47.2, - "z": 6.42 - }, - "D12": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 113.38, - "y": 47.2, - "z": 6.42 - }, - "D2": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 23.38, - "y": 47.2, - "z": 6.42 - }, - "D3": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 32.38, - "y": 47.2, - "z": 6.42 - }, - "D4": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 41.38, - "y": 47.2, - "z": 6.42 - }, - "D5": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 50.38, - "y": 47.2, - "z": 6.42 - }, - "D6": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 59.38, - "y": 47.2, - "z": 6.42 - }, - "D7": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 68.38, - "y": 47.2, - "z": 6.42 - }, - "D8": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 77.38, - "y": 47.2, - "z": 6.42 - }, - "D9": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 86.38, - "y": 47.2, - "z": 6.42 - }, - "E1": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 14.38, - "y": 38.2, - "z": 6.42 - }, - "E10": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 95.38, - "y": 38.2, - "z": 6.42 - }, - "E11": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 104.38, - "y": 38.2, - "z": 6.42 - }, - "E12": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 113.38, - "y": 38.2, - "z": 6.42 - }, - "E2": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 23.38, - "y": 38.2, - "z": 6.42 - }, - "E3": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 32.38, - "y": 38.2, - "z": 6.42 - }, - "E4": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 41.38, - "y": 38.2, - "z": 6.42 - }, - "E5": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 50.38, - "y": 38.2, - "z": 6.42 - }, - "E6": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 59.38, - "y": 38.2, - "z": 6.42 - }, - "E7": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 68.38, - "y": 38.2, - "z": 6.42 - }, - "E8": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 77.38, - "y": 38.2, - "z": 6.42 - }, - "E9": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 86.38, - "y": 38.2, - "z": 6.42 - }, - "F1": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 14.38, - "y": 29.2, - "z": 6.42 - }, - "F10": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 95.38, - "y": 29.2, - "z": 6.42 - }, - "F11": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 104.38, - "y": 29.2, - "z": 6.42 - }, - "F12": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 113.38, - "y": 29.2, - "z": 6.42 - }, - "F2": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 23.38, - "y": 29.2, - "z": 6.42 - }, - "F3": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 32.38, - "y": 29.2, - "z": 6.42 - }, - "F4": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 41.38, - "y": 29.2, - "z": 6.42 - }, - "F5": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 50.38, - "y": 29.2, - "z": 6.42 - }, - "F6": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 59.38, - "y": 29.2, - "z": 6.42 - }, - "F7": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 68.38, - "y": 29.2, - "z": 6.42 - }, - "F8": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 77.38, - "y": 29.2, - "z": 6.42 - }, - "F9": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 86.38, - "y": 29.2, - "z": 6.42 - }, - "G1": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 14.38, - "y": 20.2, - "z": 6.42 - }, - "G10": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 95.38, - "y": 20.2, - "z": 6.42 - }, - "G11": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 104.38, - "y": 20.2, - "z": 6.42 - }, - "G12": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 113.38, - "y": 20.2, - "z": 6.42 - }, - "G2": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 23.38, - "y": 20.2, - "z": 6.42 - }, - "G3": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 32.38, - "y": 20.2, - "z": 6.42 - }, - "G4": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 41.38, - "y": 20.2, - "z": 6.42 - }, - "G5": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 50.38, - "y": 20.2, - "z": 6.42 - }, - "G6": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 59.38, - "y": 20.2, - "z": 6.42 - }, - "G7": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 68.38, - "y": 20.2, - "z": 6.42 - }, - "G8": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 77.38, - "y": 20.2, - "z": 6.42 - }, - "G9": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 86.38, - "y": 20.2, - "z": 6.42 - }, - "H1": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 14.38, - "y": 11.2, - "z": 6.42 - }, - "H10": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 95.38, - "y": 11.2, - "z": 6.42 - }, - "H11": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 104.38, - "y": 11.2, - "z": 6.42 - }, - "H12": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 113.38, - "y": 11.2, - "z": 6.42 - }, - "H2": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 23.38, - "y": 11.2, - "z": 6.42 - }, - "H3": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 32.38, - "y": 11.2, - "z": 6.42 - }, - "H4": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 41.38, - "y": 11.2, - "z": 6.42 - }, - "H5": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 50.38, - "y": 11.2, - "z": 6.42 - }, - "H6": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 59.38, - "y": 11.2, - "z": 6.42 - }, - "H7": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 68.38, - "y": 11.2, - "z": 6.42 - }, - "H8": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 77.38, - "y": 11.2, - "z": 6.42 - }, - "H9": { - "depth": 14.78, - "diameter": 5.34, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 86.38, - "y": 11.2, - "z": 6.42 - } - } - } - }, - "status": "succeeded" - }, - { - "commandType": "loadLabware", - "notes": [], - "params": { - "displayName": "Liquid Waste", - "loadName": "nest_1_reservoir_195ml", - "location": { - "slotName": "9" - }, - "namespace": "opentrons", - "version": 1 - }, - "result": { - "definition": { - "allowedRoles": [], - "brand": { - "brand": "NEST", - "brandId": [ - "360103" - ], - "links": [ - "https://www.nest-biotech.com/reagent-reserviors/59178416.html" - ] - }, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - }, - "dimensions": { - "xDimension": 127.76, - "yDimension": 85.48, - "zDimension": 31.4 - }, - "gripperOffsets": {}, - "groups": [ - { - "metadata": { - "wellBottomShape": "v" - }, - "wells": [ - "A1" - ] - } - ], - "metadata": { - "displayCategory": "reservoir", - "displayName": "NEST 1 Well Reservoir 195 mL", - "displayVolumeUnits": "mL", - "tags": [] - }, - "namespace": "opentrons", - "ordering": [ - [ - "A1" - ] - ], - "parameters": { - "format": "trough", - "isMagneticModuleCompatible": false, - "isTiprack": false, - "loadName": "nest_1_reservoir_195ml", - "quirks": [ - "centerMultichannelOnWells", - "touchTipDisabled" - ] - }, - "schemaVersion": 2, - "stackingOffsetWithLabware": {}, - "stackingOffsetWithModule": {}, - "version": 1, - "wells": { - "A1": { - "depth": 25, - "shape": "rectangular", - "totalLiquidVolume": 195000, - "x": 63.88, - "xDimension": 106.8, - "y": 42.74, - "yDimension": 71.2, - "z": 4.55 - } - } - } - }, - "status": "succeeded" - }, - { - "commandType": "loadLabware", - "notes": [], - "params": { - "displayName": "reagent reservoir 2", - "loadName": "nest_12_reservoir_15ml", - "location": { - "slotName": "3" - }, - "namespace": "opentrons", - "version": 1 - }, - "result": { - "definition": { - "allowedRoles": [], - "brand": { - "brand": "NEST", - "brandId": [ - "360102" - ], - "links": [ - "https://www.nest-biotech.com/reagent-reserviors/59178414.html" - ] - }, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - }, - "dimensions": { - "xDimension": 127.76, - "yDimension": 85.48, - "zDimension": 31.4 - }, - "gripperOffsets": {}, - "groups": [ - { - "metadata": { - "wellBottomShape": "v" - }, - "wells": [ - "A1", - "A10", - "A11", - "A12", - "A2", - "A3", - "A4", - "A5", - "A6", - "A7", - "A8", - "A9" - ] - } - ], - "metadata": { - "displayCategory": "reservoir", - "displayName": "NEST 12 Well Reservoir 15 mL", - "displayVolumeUnits": "mL", - "tags": [] - }, - "namespace": "opentrons", - "ordering": [ - [ - "A1" - ], - [ - "A10" - ], - [ - "A11" - ], - [ - "A12" - ], - [ - "A2" - ], - [ - "A3" - ], - [ - "A4" - ], - [ - "A5" - ], - [ - "A6" - ], - [ - "A7" - ], - [ - "A8" - ], - [ - "A9" - ] - ], - "parameters": { - "format": "trough", - "isMagneticModuleCompatible": false, - "isTiprack": false, - "loadName": "nest_12_reservoir_15ml", - "quirks": [ - "centerMultichannelOnWells", - "touchTipDisabled" - ] - }, - "schemaVersion": 2, - "stackingOffsetWithLabware": {}, - "stackingOffsetWithModule": {}, - "version": 1, - "wells": { - "A1": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 14.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A10": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 95.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A11": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 104.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A12": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 113.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A2": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 23.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A3": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 32.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A4": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 41.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A5": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 50.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A6": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 59.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A7": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 68.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A8": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 77.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A9": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 86.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - } - } - } - }, - "status": "succeeded" - }, - { - "commandType": "loadLabware", - "notes": [], - "params": { - "displayName": "reagent reservoir 1", - "loadName": "nest_12_reservoir_15ml", - "location": { - "slotName": "2" - }, - "namespace": "opentrons", - "version": 1 - }, - "result": { - "definition": { - "allowedRoles": [], - "brand": { - "brand": "NEST", - "brandId": [ - "360102" - ], - "links": [ - "https://www.nest-biotech.com/reagent-reserviors/59178414.html" - ] - }, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - }, - "dimensions": { - "xDimension": 127.76, - "yDimension": 85.48, - "zDimension": 31.4 - }, - "gripperOffsets": {}, - "groups": [ - { - "metadata": { - "wellBottomShape": "v" - }, - "wells": [ - "A1", - "A10", - "A11", - "A12", - "A2", - "A3", - "A4", - "A5", - "A6", - "A7", - "A8", - "A9" - ] - } - ], - "metadata": { - "displayCategory": "reservoir", - "displayName": "NEST 12 Well Reservoir 15 mL", - "displayVolumeUnits": "mL", - "tags": [] - }, - "namespace": "opentrons", - "ordering": [ - [ - "A1" - ], - [ - "A10" - ], - [ - "A11" - ], - [ - "A12" - ], - [ - "A2" - ], - [ - "A3" - ], - [ - "A4" - ], - [ - "A5" - ], - [ - "A6" - ], - [ - "A7" - ], - [ - "A8" - ], - [ - "A9" - ] - ], - "parameters": { - "format": "trough", - "isMagneticModuleCompatible": false, - "isTiprack": false, - "loadName": "nest_12_reservoir_15ml", - "quirks": [ - "centerMultichannelOnWells", - "touchTipDisabled" - ] - }, - "schemaVersion": 2, - "stackingOffsetWithLabware": {}, - "stackingOffsetWithModule": {}, - "version": 1, - "wells": { - "A1": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 14.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A10": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 95.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A11": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 104.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A12": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 113.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A2": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 23.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A3": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 32.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A4": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 41.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A5": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 50.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A6": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 59.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A7": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 68.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A8": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 77.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - }, - "A9": { - "depth": 26.85, - "shape": "rectangular", - "totalLiquidVolume": 15000, - "x": 86.38, - "xDimension": 8.2, - "y": 42.78, - "yDimension": 71.2, - "z": 4.55 - } - } - } - }, - "status": "succeeded" - }, - { - "commandType": "loadLabware", - "notes": [], - "params": { - "displayName": "200µl filtertiprack", - "loadName": "opentrons_96_tiprack_300ul", - "location": { - "slotName": "5" - }, - "namespace": "opentrons", - "version": 1 - }, - "result": { - "definition": { - "allowedRoles": [], - "brand": { - "brand": "Opentrons", - "brandId": [], - "links": [ - "https://shop.opentrons.com/collections/opentrons-tips/products/opentrons-300ul-tips" - ] - }, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - }, - "dimensions": { - "xDimension": 127.76, - "yDimension": 85.48, - "zDimension": 64.49 - }, - "gripperOffsets": {}, - "groups": [ - { - "metadata": {}, - "wells": [ - "A1", - "A10", - "A11", - "A12", - "A2", - "A3", - "A4", - "A5", - "A6", - "A7", - "A8", - "A9", - "B1", - "B10", - "B11", - "B12", - "B2", - "B3", - "B4", - "B5", - "B6", - "B7", - "B8", - "B9", - "C1", - "C10", - "C11", - "C12", - "C2", - "C3", - "C4", - "C5", - "C6", - "C7", - "C8", - "C9", - "D1", - "D10", - "D11", - "D12", - "D2", - "D3", - "D4", - "D5", - "D6", - "D7", - "D8", - "D9", - "E1", - "E10", - "E11", - "E12", - "E2", - "E3", - "E4", - "E5", - "E6", - "E7", - "E8", - "E9", - "F1", - "F10", - "F11", - "F12", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - "F8", - "F9", - "G1", - "G10", - "G11", - "G12", - "G2", - "G3", - "G4", - "G5", - "G6", - "G7", - "G8", - "G9", - "H1", - "H10", - "H11", - "H12", - "H2", - "H3", - "H4", - "H5", - "H6", - "H7", - "H8", - "H9" - ] - } - ], - "metadata": { - "displayCategory": "tipRack", - "displayName": "Opentrons OT-2 96 Tip Rack 300 µL", - "displayVolumeUnits": "µL", - "tags": [] - }, - "namespace": "opentrons", - "ordering": [ - [ - "A1", - "B1", - "C1", - "D1", - "E1", - "F1", - "G1", - "H1" - ], - [ - "A10", - "B10", - "C10", - "D10", - "E10", - "F10", - "G10", - "H10" - ], - [ - "A11", - "B11", - "C11", - "D11", - "E11", - "F11", - "G11", - "H11" - ], - [ - "A12", - "B12", - "C12", - "D12", - "E12", - "F12", - "G12", - "H12" - ], - [ - "A2", - "B2", - "C2", - "D2", - "E2", - "F2", - "G2", - "H2" - ], - [ - "A3", - "B3", - "C3", - "D3", - "E3", - "F3", - "G3", - "H3" - ], - [ - "A4", - "B4", - "C4", - "D4", - "E4", - "F4", - "G4", - "H4" - ], - [ - "A5", - "B5", - "C5", - "D5", - "E5", - "F5", - "G5", - "H5" - ], - [ - "A6", - "B6", - "C6", - "D6", - "E6", - "F6", - "G6", - "H6" - ], - [ - "A7", - "B7", - "C7", - "D7", - "E7", - "F7", - "G7", - "H7" - ], - [ - "A8", - "B8", - "C8", - "D8", - "E8", - "F8", - "G8", - "H8" - ], - [ - "A9", - "B9", - "C9", - "D9", - "E9", - "F9", - "G9", - "H9" - ] - ], - "parameters": { - "format": "96Standard", - "isMagneticModuleCompatible": false, - "isTiprack": true, - "loadName": "opentrons_96_tiprack_300ul", - "tipLength": 59.3, - "tipOverlap": 7.47 - }, - "schemaVersion": 2, - "stackingOffsetWithLabware": {}, - "stackingOffsetWithModule": {}, - "version": 1, - "wells": { - "A1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 74.24, - "z": 5.39 - }, - "A10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 74.24, - "z": 5.39 - }, - "A11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 74.24, - "z": 5.39 - }, - "A12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 74.24, - "z": 5.39 - }, - "A2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 74.24, - "z": 5.39 - }, - "A3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 74.24, - "z": 5.39 - }, - "A4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 74.24, - "z": 5.39 - }, - "A5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 74.24, - "z": 5.39 - }, - "A6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 74.24, - "z": 5.39 - }, - "A7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 74.24, - "z": 5.39 - }, - "A8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 74.24, - "z": 5.39 - }, - "A9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 74.24, - "z": 5.39 - }, - "B1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 65.24, - "z": 5.39 - }, - "B10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 65.24, - "z": 5.39 - }, - "B11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 65.24, - "z": 5.39 - }, - "B12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 65.24, - "z": 5.39 - }, - "B2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 65.24, - "z": 5.39 - }, - "B3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 65.24, - "z": 5.39 - }, - "B4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 65.24, - "z": 5.39 - }, - "B5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 65.24, - "z": 5.39 - }, - "B6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 65.24, - "z": 5.39 - }, - "B7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 65.24, - "z": 5.39 - }, - "B8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 65.24, - "z": 5.39 - }, - "B9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 65.24, - "z": 5.39 - }, - "C1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 56.24, - "z": 5.39 - }, - "C10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 56.24, - "z": 5.39 - }, - "C11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 56.24, - "z": 5.39 - }, - "C12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 56.24, - "z": 5.39 - }, - "C2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 56.24, - "z": 5.39 - }, - "C3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 56.24, - "z": 5.39 - }, - "C4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 56.24, - "z": 5.39 - }, - "C5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 56.24, - "z": 5.39 - }, - "C6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 56.24, - "z": 5.39 - }, - "C7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 56.24, - "z": 5.39 - }, - "C8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 56.24, - "z": 5.39 - }, - "C9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 56.24, - "z": 5.39 - }, - "D1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 47.24, - "z": 5.39 - }, - "D10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 47.24, - "z": 5.39 - }, - "D11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 47.24, - "z": 5.39 - }, - "D12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 47.24, - "z": 5.39 - }, - "D2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 47.24, - "z": 5.39 - }, - "D3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 47.24, - "z": 5.39 - }, - "D4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 47.24, - "z": 5.39 - }, - "D5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 47.24, - "z": 5.39 - }, - "D6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 47.24, - "z": 5.39 - }, - "D7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 47.24, - "z": 5.39 - }, - "D8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 47.24, - "z": 5.39 - }, - "D9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 47.24, - "z": 5.39 - }, - "E1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 38.24, - "z": 5.39 - }, - "E10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 38.24, - "z": 5.39 - }, - "E11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 38.24, - "z": 5.39 - }, - "E12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 38.24, - "z": 5.39 - }, - "E2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 38.24, - "z": 5.39 - }, - "E3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 38.24, - "z": 5.39 - }, - "E4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 38.24, - "z": 5.39 - }, - "E5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 38.24, - "z": 5.39 - }, - "E6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 38.24, - "z": 5.39 - }, - "E7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 38.24, - "z": 5.39 - }, - "E8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 38.24, - "z": 5.39 - }, - "E9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 38.24, - "z": 5.39 - }, - "F1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 29.24, - "z": 5.39 - }, - "F10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 29.24, - "z": 5.39 - }, - "F11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 29.24, - "z": 5.39 - }, - "F12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 29.24, - "z": 5.39 - }, - "F2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 29.24, - "z": 5.39 - }, - "F3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 29.24, - "z": 5.39 - }, - "F4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 29.24, - "z": 5.39 - }, - "F5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 29.24, - "z": 5.39 - }, - "F6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 29.24, - "z": 5.39 - }, - "F7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 29.24, - "z": 5.39 - }, - "F8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 29.24, - "z": 5.39 - }, - "F9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 29.24, - "z": 5.39 - }, - "G1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 20.24, - "z": 5.39 - }, - "G10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 20.24, - "z": 5.39 - }, - "G11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 20.24, - "z": 5.39 - }, - "G12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 20.24, - "z": 5.39 - }, - "G2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 20.24, - "z": 5.39 - }, - "G3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 20.24, - "z": 5.39 - }, - "G4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 20.24, - "z": 5.39 - }, - "G5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 20.24, - "z": 5.39 - }, - "G6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 20.24, - "z": 5.39 - }, - "G7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 20.24, - "z": 5.39 - }, - "G8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 20.24, - "z": 5.39 - }, - "G9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 20.24, - "z": 5.39 - }, - "H1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 11.24, - "z": 5.39 - }, - "H10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 11.24, - "z": 5.39 - }, - "H11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 11.24, - "z": 5.39 - }, - "H12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 11.24, - "z": 5.39 - }, - "H2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 11.24, - "z": 5.39 - }, - "H3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 11.24, - "z": 5.39 - }, - "H4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 11.24, - "z": 5.39 - }, - "H5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 11.24, - "z": 5.39 - }, - "H6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 11.24, - "z": 5.39 - }, - "H7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 11.24, - "z": 5.39 - }, - "H8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 11.24, - "z": 5.39 - }, - "H9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 11.24, - "z": 5.39 - } - } - } - }, - "status": "succeeded" - }, - { - "commandType": "loadLabware", - "notes": [], - "params": { - "displayName": "200µl filtertiprack", - "loadName": "opentrons_96_tiprack_300ul", - "location": { - "slotName": "7" - }, - "namespace": "opentrons", - "version": 1 - }, - "result": { - "definition": { - "allowedRoles": [], - "brand": { - "brand": "Opentrons", - "brandId": [], - "links": [ - "https://shop.opentrons.com/collections/opentrons-tips/products/opentrons-300ul-tips" - ] - }, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - }, - "dimensions": { - "xDimension": 127.76, - "yDimension": 85.48, - "zDimension": 64.49 - }, - "gripperOffsets": {}, - "groups": [ - { - "metadata": {}, - "wells": [ - "A1", - "A10", - "A11", - "A12", - "A2", - "A3", - "A4", - "A5", - "A6", - "A7", - "A8", - "A9", - "B1", - "B10", - "B11", - "B12", - "B2", - "B3", - "B4", - "B5", - "B6", - "B7", - "B8", - "B9", - "C1", - "C10", - "C11", - "C12", - "C2", - "C3", - "C4", - "C5", - "C6", - "C7", - "C8", - "C9", - "D1", - "D10", - "D11", - "D12", - "D2", - "D3", - "D4", - "D5", - "D6", - "D7", - "D8", - "D9", - "E1", - "E10", - "E11", - "E12", - "E2", - "E3", - "E4", - "E5", - "E6", - "E7", - "E8", - "E9", - "F1", - "F10", - "F11", - "F12", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - "F8", - "F9", - "G1", - "G10", - "G11", - "G12", - "G2", - "G3", - "G4", - "G5", - "G6", - "G7", - "G8", - "G9", - "H1", - "H10", - "H11", - "H12", - "H2", - "H3", - "H4", - "H5", - "H6", - "H7", - "H8", - "H9" - ] - } - ], - "metadata": { - "displayCategory": "tipRack", - "displayName": "Opentrons OT-2 96 Tip Rack 300 µL", - "displayVolumeUnits": "µL", - "tags": [] - }, - "namespace": "opentrons", - "ordering": [ - [ - "A1", - "B1", - "C1", - "D1", - "E1", - "F1", - "G1", - "H1" - ], - [ - "A10", - "B10", - "C10", - "D10", - "E10", - "F10", - "G10", - "H10" - ], - [ - "A11", - "B11", - "C11", - "D11", - "E11", - "F11", - "G11", - "H11" - ], - [ - "A12", - "B12", - "C12", - "D12", - "E12", - "F12", - "G12", - "H12" - ], - [ - "A2", - "B2", - "C2", - "D2", - "E2", - "F2", - "G2", - "H2" - ], - [ - "A3", - "B3", - "C3", - "D3", - "E3", - "F3", - "G3", - "H3" - ], - [ - "A4", - "B4", - "C4", - "D4", - "E4", - "F4", - "G4", - "H4" - ], - [ - "A5", - "B5", - "C5", - "D5", - "E5", - "F5", - "G5", - "H5" - ], - [ - "A6", - "B6", - "C6", - "D6", - "E6", - "F6", - "G6", - "H6" - ], - [ - "A7", - "B7", - "C7", - "D7", - "E7", - "F7", - "G7", - "H7" - ], - [ - "A8", - "B8", - "C8", - "D8", - "E8", - "F8", - "G8", - "H8" - ], - [ - "A9", - "B9", - "C9", - "D9", - "E9", - "F9", - "G9", - "H9" - ] - ], - "parameters": { - "format": "96Standard", - "isMagneticModuleCompatible": false, - "isTiprack": true, - "loadName": "opentrons_96_tiprack_300ul", - "tipLength": 59.3, - "tipOverlap": 7.47 - }, - "schemaVersion": 2, - "stackingOffsetWithLabware": {}, - "stackingOffsetWithModule": {}, - "version": 1, - "wells": { - "A1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 74.24, - "z": 5.39 - }, - "A10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 74.24, - "z": 5.39 - }, - "A11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 74.24, - "z": 5.39 - }, - "A12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 74.24, - "z": 5.39 - }, - "A2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 74.24, - "z": 5.39 - }, - "A3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 74.24, - "z": 5.39 - }, - "A4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 74.24, - "z": 5.39 - }, - "A5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 74.24, - "z": 5.39 - }, - "A6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 74.24, - "z": 5.39 - }, - "A7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 74.24, - "z": 5.39 - }, - "A8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 74.24, - "z": 5.39 - }, - "A9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 74.24, - "z": 5.39 - }, - "B1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 65.24, - "z": 5.39 - }, - "B10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 65.24, - "z": 5.39 - }, - "B11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 65.24, - "z": 5.39 - }, - "B12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 65.24, - "z": 5.39 - }, - "B2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 65.24, - "z": 5.39 - }, - "B3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 65.24, - "z": 5.39 - }, - "B4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 65.24, - "z": 5.39 - }, - "B5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 65.24, - "z": 5.39 - }, - "B6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 65.24, - "z": 5.39 - }, - "B7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 65.24, - "z": 5.39 - }, - "B8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 65.24, - "z": 5.39 - }, - "B9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 65.24, - "z": 5.39 - }, - "C1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 56.24, - "z": 5.39 - }, - "C10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 56.24, - "z": 5.39 - }, - "C11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 56.24, - "z": 5.39 - }, - "C12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 56.24, - "z": 5.39 - }, - "C2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 56.24, - "z": 5.39 - }, - "C3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 56.24, - "z": 5.39 - }, - "C4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 56.24, - "z": 5.39 - }, - "C5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 56.24, - "z": 5.39 - }, - "C6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 56.24, - "z": 5.39 - }, - "C7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 56.24, - "z": 5.39 - }, - "C8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 56.24, - "z": 5.39 - }, - "C9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 56.24, - "z": 5.39 - }, - "D1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 47.24, - "z": 5.39 - }, - "D10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 47.24, - "z": 5.39 - }, - "D11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 47.24, - "z": 5.39 - }, - "D12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 47.24, - "z": 5.39 - }, - "D2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 47.24, - "z": 5.39 - }, - "D3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 47.24, - "z": 5.39 - }, - "D4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 47.24, - "z": 5.39 - }, - "D5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 47.24, - "z": 5.39 - }, - "D6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 47.24, - "z": 5.39 - }, - "D7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 47.24, - "z": 5.39 - }, - "D8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 47.24, - "z": 5.39 - }, - "D9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 47.24, - "z": 5.39 - }, - "E1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 38.24, - "z": 5.39 - }, - "E10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 38.24, - "z": 5.39 - }, - "E11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 38.24, - "z": 5.39 - }, - "E12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 38.24, - "z": 5.39 - }, - "E2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 38.24, - "z": 5.39 - }, - "E3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 38.24, - "z": 5.39 - }, - "E4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 38.24, - "z": 5.39 - }, - "E5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 38.24, - "z": 5.39 - }, - "E6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 38.24, - "z": 5.39 - }, - "E7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 38.24, - "z": 5.39 - }, - "E8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 38.24, - "z": 5.39 - }, - "E9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 38.24, - "z": 5.39 - }, - "F1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 29.24, - "z": 5.39 - }, - "F10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 29.24, - "z": 5.39 - }, - "F11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 29.24, - "z": 5.39 - }, - "F12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 29.24, - "z": 5.39 - }, - "F2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 29.24, - "z": 5.39 - }, - "F3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 29.24, - "z": 5.39 - }, - "F4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 29.24, - "z": 5.39 - }, - "F5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 29.24, - "z": 5.39 - }, - "F6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 29.24, - "z": 5.39 - }, - "F7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 29.24, - "z": 5.39 - }, - "F8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 29.24, - "z": 5.39 - }, - "F9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 29.24, - "z": 5.39 - }, - "G1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 20.24, - "z": 5.39 - }, - "G10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 20.24, - "z": 5.39 - }, - "G11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 20.24, - "z": 5.39 - }, - "G12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 20.24, - "z": 5.39 - }, - "G2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 20.24, - "z": 5.39 - }, - "G3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 20.24, - "z": 5.39 - }, - "G4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 20.24, - "z": 5.39 - }, - "G5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 20.24, - "z": 5.39 - }, - "G6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 20.24, - "z": 5.39 - }, - "G7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 20.24, - "z": 5.39 - }, - "G8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 20.24, - "z": 5.39 - }, - "G9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 20.24, - "z": 5.39 - }, - "H1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 11.24, - "z": 5.39 - }, - "H10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 11.24, - "z": 5.39 - }, - "H11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 11.24, - "z": 5.39 - }, - "H12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 11.24, - "z": 5.39 - }, - "H2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 11.24, - "z": 5.39 - }, - "H3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 11.24, - "z": 5.39 - }, - "H4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 11.24, - "z": 5.39 - }, - "H5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 11.24, - "z": 5.39 - }, - "H6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 11.24, - "z": 5.39 - }, - "H7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 11.24, - "z": 5.39 - }, - "H8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 11.24, - "z": 5.39 - }, - "H9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 11.24, - "z": 5.39 - } - } - } - }, - "status": "succeeded" - }, - { - "commandType": "loadLabware", - "notes": [], - "params": { - "displayName": "200µl filtertiprack", - "loadName": "opentrons_96_tiprack_300ul", - "location": { - "slotName": "8" - }, - "namespace": "opentrons", - "version": 1 - }, - "result": { - "definition": { - "allowedRoles": [], - "brand": { - "brand": "Opentrons", - "brandId": [], - "links": [ - "https://shop.opentrons.com/collections/opentrons-tips/products/opentrons-300ul-tips" - ] - }, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - }, - "dimensions": { - "xDimension": 127.76, - "yDimension": 85.48, - "zDimension": 64.49 - }, - "gripperOffsets": {}, - "groups": [ - { - "metadata": {}, - "wells": [ - "A1", - "A10", - "A11", - "A12", - "A2", - "A3", - "A4", - "A5", - "A6", - "A7", - "A8", - "A9", - "B1", - "B10", - "B11", - "B12", - "B2", - "B3", - "B4", - "B5", - "B6", - "B7", - "B8", - "B9", - "C1", - "C10", - "C11", - "C12", - "C2", - "C3", - "C4", - "C5", - "C6", - "C7", - "C8", - "C9", - "D1", - "D10", - "D11", - "D12", - "D2", - "D3", - "D4", - "D5", - "D6", - "D7", - "D8", - "D9", - "E1", - "E10", - "E11", - "E12", - "E2", - "E3", - "E4", - "E5", - "E6", - "E7", - "E8", - "E9", - "F1", - "F10", - "F11", - "F12", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - "F8", - "F9", - "G1", - "G10", - "G11", - "G12", - "G2", - "G3", - "G4", - "G5", - "G6", - "G7", - "G8", - "G9", - "H1", - "H10", - "H11", - "H12", - "H2", - "H3", - "H4", - "H5", - "H6", - "H7", - "H8", - "H9" - ] - } - ], - "metadata": { - "displayCategory": "tipRack", - "displayName": "Opentrons OT-2 96 Tip Rack 300 µL", - "displayVolumeUnits": "µL", - "tags": [] - }, - "namespace": "opentrons", - "ordering": [ - [ - "A1", - "B1", - "C1", - "D1", - "E1", - "F1", - "G1", - "H1" - ], - [ - "A10", - "B10", - "C10", - "D10", - "E10", - "F10", - "G10", - "H10" - ], - [ - "A11", - "B11", - "C11", - "D11", - "E11", - "F11", - "G11", - "H11" - ], - [ - "A12", - "B12", - "C12", - "D12", - "E12", - "F12", - "G12", - "H12" - ], - [ - "A2", - "B2", - "C2", - "D2", - "E2", - "F2", - "G2", - "H2" - ], - [ - "A3", - "B3", - "C3", - "D3", - "E3", - "F3", - "G3", - "H3" - ], - [ - "A4", - "B4", - "C4", - "D4", - "E4", - "F4", - "G4", - "H4" - ], - [ - "A5", - "B5", - "C5", - "D5", - "E5", - "F5", - "G5", - "H5" - ], - [ - "A6", - "B6", - "C6", - "D6", - "E6", - "F6", - "G6", - "H6" - ], - [ - "A7", - "B7", - "C7", - "D7", - "E7", - "F7", - "G7", - "H7" - ], - [ - "A8", - "B8", - "C8", - "D8", - "E8", - "F8", - "G8", - "H8" - ], - [ - "A9", - "B9", - "C9", - "D9", - "E9", - "F9", - "G9", - "H9" - ] - ], - "parameters": { - "format": "96Standard", - "isMagneticModuleCompatible": false, - "isTiprack": true, - "loadName": "opentrons_96_tiprack_300ul", - "tipLength": 59.3, - "tipOverlap": 7.47 - }, - "schemaVersion": 2, - "stackingOffsetWithLabware": {}, - "stackingOffsetWithModule": {}, - "version": 1, - "wells": { - "A1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 74.24, - "z": 5.39 - }, - "A10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 74.24, - "z": 5.39 - }, - "A11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 74.24, - "z": 5.39 - }, - "A12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 74.24, - "z": 5.39 - }, - "A2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 74.24, - "z": 5.39 - }, - "A3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 74.24, - "z": 5.39 - }, - "A4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 74.24, - "z": 5.39 - }, - "A5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 74.24, - "z": 5.39 - }, - "A6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 74.24, - "z": 5.39 - }, - "A7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 74.24, - "z": 5.39 - }, - "A8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 74.24, - "z": 5.39 - }, - "A9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 74.24, - "z": 5.39 - }, - "B1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 65.24, - "z": 5.39 - }, - "B10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 65.24, - "z": 5.39 - }, - "B11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 65.24, - "z": 5.39 - }, - "B12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 65.24, - "z": 5.39 - }, - "B2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 65.24, - "z": 5.39 - }, - "B3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 65.24, - "z": 5.39 - }, - "B4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 65.24, - "z": 5.39 - }, - "B5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 65.24, - "z": 5.39 - }, - "B6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 65.24, - "z": 5.39 - }, - "B7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 65.24, - "z": 5.39 - }, - "B8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 65.24, - "z": 5.39 - }, - "B9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 65.24, - "z": 5.39 - }, - "C1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 56.24, - "z": 5.39 - }, - "C10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 56.24, - "z": 5.39 - }, - "C11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 56.24, - "z": 5.39 - }, - "C12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 56.24, - "z": 5.39 - }, - "C2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 56.24, - "z": 5.39 - }, - "C3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 56.24, - "z": 5.39 - }, - "C4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 56.24, - "z": 5.39 - }, - "C5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 56.24, - "z": 5.39 - }, - "C6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 56.24, - "z": 5.39 - }, - "C7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 56.24, - "z": 5.39 - }, - "C8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 56.24, - "z": 5.39 - }, - "C9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 56.24, - "z": 5.39 - }, - "D1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 47.24, - "z": 5.39 - }, - "D10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 47.24, - "z": 5.39 - }, - "D11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 47.24, - "z": 5.39 - }, - "D12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 47.24, - "z": 5.39 - }, - "D2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 47.24, - "z": 5.39 - }, - "D3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 47.24, - "z": 5.39 - }, - "D4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 47.24, - "z": 5.39 - }, - "D5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 47.24, - "z": 5.39 - }, - "D6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 47.24, - "z": 5.39 - }, - "D7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 47.24, - "z": 5.39 - }, - "D8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 47.24, - "z": 5.39 - }, - "D9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 47.24, - "z": 5.39 - }, - "E1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 38.24, - "z": 5.39 - }, - "E10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 38.24, - "z": 5.39 - }, - "E11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 38.24, - "z": 5.39 - }, - "E12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 38.24, - "z": 5.39 - }, - "E2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 38.24, - "z": 5.39 - }, - "E3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 38.24, - "z": 5.39 - }, - "E4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 38.24, - "z": 5.39 - }, - "E5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 38.24, - "z": 5.39 - }, - "E6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 38.24, - "z": 5.39 - }, - "E7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 38.24, - "z": 5.39 - }, - "E8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 38.24, - "z": 5.39 - }, - "E9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 38.24, - "z": 5.39 - }, - "F1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 29.24, - "z": 5.39 - }, - "F10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 29.24, - "z": 5.39 - }, - "F11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 29.24, - "z": 5.39 - }, - "F12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 29.24, - "z": 5.39 - }, - "F2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 29.24, - "z": 5.39 - }, - "F3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 29.24, - "z": 5.39 - }, - "F4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 29.24, - "z": 5.39 - }, - "F5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 29.24, - "z": 5.39 - }, - "F6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 29.24, - "z": 5.39 - }, - "F7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 29.24, - "z": 5.39 - }, - "F8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 29.24, - "z": 5.39 - }, - "F9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 29.24, - "z": 5.39 - }, - "G1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 20.24, - "z": 5.39 - }, - "G10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 20.24, - "z": 5.39 - }, - "G11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 20.24, - "z": 5.39 - }, - "G12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 20.24, - "z": 5.39 - }, - "G2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 20.24, - "z": 5.39 - }, - "G3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 20.24, - "z": 5.39 - }, - "G4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 20.24, - "z": 5.39 - }, - "G5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 20.24, - "z": 5.39 - }, - "G6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 20.24, - "z": 5.39 - }, - "G7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 20.24, - "z": 5.39 - }, - "G8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 20.24, - "z": 5.39 - }, - "G9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 20.24, - "z": 5.39 - }, - "H1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 11.24, - "z": 5.39 - }, - "H10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 11.24, - "z": 5.39 - }, - "H11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 11.24, - "z": 5.39 - }, - "H12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 11.24, - "z": 5.39 - }, - "H2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 11.24, - "z": 5.39 - }, - "H3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 11.24, - "z": 5.39 - }, - "H4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 11.24, - "z": 5.39 - }, - "H5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 11.24, - "z": 5.39 - }, - "H6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 11.24, - "z": 5.39 - }, - "H7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 11.24, - "z": 5.39 - }, - "H8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 11.24, - "z": 5.39 - }, - "H9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 11.24, - "z": 5.39 - } - } - } - }, - "status": "succeeded" - }, - { - "commandType": "loadLabware", - "notes": [], - "params": { - "displayName": "200µl filtertiprack", - "loadName": "opentrons_96_tiprack_300ul", - "location": { - "slotName": "10" - }, - "namespace": "opentrons", - "version": 1 - }, - "result": { - "definition": { - "allowedRoles": [], - "brand": { - "brand": "Opentrons", - "brandId": [], - "links": [ - "https://shop.opentrons.com/collections/opentrons-tips/products/opentrons-300ul-tips" - ] - }, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - }, - "dimensions": { - "xDimension": 127.76, - "yDimension": 85.48, - "zDimension": 64.49 - }, - "gripperOffsets": {}, - "groups": [ - { - "metadata": {}, - "wells": [ - "A1", - "A10", - "A11", - "A12", - "A2", - "A3", - "A4", - "A5", - "A6", - "A7", - "A8", - "A9", - "B1", - "B10", - "B11", - "B12", - "B2", - "B3", - "B4", - "B5", - "B6", - "B7", - "B8", - "B9", - "C1", - "C10", - "C11", - "C12", - "C2", - "C3", - "C4", - "C5", - "C6", - "C7", - "C8", - "C9", - "D1", - "D10", - "D11", - "D12", - "D2", - "D3", - "D4", - "D5", - "D6", - "D7", - "D8", - "D9", - "E1", - "E10", - "E11", - "E12", - "E2", - "E3", - "E4", - "E5", - "E6", - "E7", - "E8", - "E9", - "F1", - "F10", - "F11", - "F12", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - "F8", - "F9", - "G1", - "G10", - "G11", - "G12", - "G2", - "G3", - "G4", - "G5", - "G6", - "G7", - "G8", - "G9", - "H1", - "H10", - "H11", - "H12", - "H2", - "H3", - "H4", - "H5", - "H6", - "H7", - "H8", - "H9" - ] - } - ], - "metadata": { - "displayCategory": "tipRack", - "displayName": "Opentrons OT-2 96 Tip Rack 300 µL", - "displayVolumeUnits": "µL", - "tags": [] - }, - "namespace": "opentrons", - "ordering": [ - [ - "A1", - "B1", - "C1", - "D1", - "E1", - "F1", - "G1", - "H1" - ], - [ - "A10", - "B10", - "C10", - "D10", - "E10", - "F10", - "G10", - "H10" - ], - [ - "A11", - "B11", - "C11", - "D11", - "E11", - "F11", - "G11", - "H11" - ], - [ - "A12", - "B12", - "C12", - "D12", - "E12", - "F12", - "G12", - "H12" - ], - [ - "A2", - "B2", - "C2", - "D2", - "E2", - "F2", - "G2", - "H2" - ], - [ - "A3", - "B3", - "C3", - "D3", - "E3", - "F3", - "G3", - "H3" - ], - [ - "A4", - "B4", - "C4", - "D4", - "E4", - "F4", - "G4", - "H4" - ], - [ - "A5", - "B5", - "C5", - "D5", - "E5", - "F5", - "G5", - "H5" - ], - [ - "A6", - "B6", - "C6", - "D6", - "E6", - "F6", - "G6", - "H6" - ], - [ - "A7", - "B7", - "C7", - "D7", - "E7", - "F7", - "G7", - "H7" - ], - [ - "A8", - "B8", - "C8", - "D8", - "E8", - "F8", - "G8", - "H8" - ], - [ - "A9", - "B9", - "C9", - "D9", - "E9", - "F9", - "G9", - "H9" - ] - ], - "parameters": { - "format": "96Standard", - "isMagneticModuleCompatible": false, - "isTiprack": true, - "loadName": "opentrons_96_tiprack_300ul", - "tipLength": 59.3, - "tipOverlap": 7.47 - }, - "schemaVersion": 2, - "stackingOffsetWithLabware": {}, - "stackingOffsetWithModule": {}, - "version": 1, - "wells": { - "A1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 74.24, - "z": 5.39 - }, - "A10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 74.24, - "z": 5.39 - }, - "A11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 74.24, - "z": 5.39 - }, - "A12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 74.24, - "z": 5.39 - }, - "A2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 74.24, - "z": 5.39 - }, - "A3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 74.24, - "z": 5.39 - }, - "A4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 74.24, - "z": 5.39 - }, - "A5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 74.24, - "z": 5.39 - }, - "A6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 74.24, - "z": 5.39 - }, - "A7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 74.24, - "z": 5.39 - }, - "A8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 74.24, - "z": 5.39 - }, - "A9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 74.24, - "z": 5.39 - }, - "B1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 65.24, - "z": 5.39 - }, - "B10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 65.24, - "z": 5.39 - }, - "B11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 65.24, - "z": 5.39 - }, - "B12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 65.24, - "z": 5.39 - }, - "B2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 65.24, - "z": 5.39 - }, - "B3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 65.24, - "z": 5.39 - }, - "B4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 65.24, - "z": 5.39 - }, - "B5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 65.24, - "z": 5.39 - }, - "B6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 65.24, - "z": 5.39 - }, - "B7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 65.24, - "z": 5.39 - }, - "B8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 65.24, - "z": 5.39 - }, - "B9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 65.24, - "z": 5.39 - }, - "C1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 56.24, - "z": 5.39 - }, - "C10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 56.24, - "z": 5.39 - }, - "C11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 56.24, - "z": 5.39 - }, - "C12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 56.24, - "z": 5.39 - }, - "C2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 56.24, - "z": 5.39 - }, - "C3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 56.24, - "z": 5.39 - }, - "C4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 56.24, - "z": 5.39 - }, - "C5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 56.24, - "z": 5.39 - }, - "C6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 56.24, - "z": 5.39 - }, - "C7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 56.24, - "z": 5.39 - }, - "C8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 56.24, - "z": 5.39 - }, - "C9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 56.24, - "z": 5.39 - }, - "D1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 47.24, - "z": 5.39 - }, - "D10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 47.24, - "z": 5.39 - }, - "D11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 47.24, - "z": 5.39 - }, - "D12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 47.24, - "z": 5.39 - }, - "D2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 47.24, - "z": 5.39 - }, - "D3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 47.24, - "z": 5.39 - }, - "D4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 47.24, - "z": 5.39 - }, - "D5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 47.24, - "z": 5.39 - }, - "D6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 47.24, - "z": 5.39 - }, - "D7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 47.24, - "z": 5.39 - }, - "D8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 47.24, - "z": 5.39 - }, - "D9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 47.24, - "z": 5.39 - }, - "E1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 38.24, - "z": 5.39 - }, - "E10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 38.24, - "z": 5.39 - }, - "E11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 38.24, - "z": 5.39 - }, - "E12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 38.24, - "z": 5.39 - }, - "E2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 38.24, - "z": 5.39 - }, - "E3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 38.24, - "z": 5.39 - }, - "E4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 38.24, - "z": 5.39 - }, - "E5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 38.24, - "z": 5.39 - }, - "E6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 38.24, - "z": 5.39 - }, - "E7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 38.24, - "z": 5.39 - }, - "E8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 38.24, - "z": 5.39 - }, - "E9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 38.24, - "z": 5.39 - }, - "F1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 29.24, - "z": 5.39 - }, - "F10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 29.24, - "z": 5.39 - }, - "F11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 29.24, - "z": 5.39 - }, - "F12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 29.24, - "z": 5.39 - }, - "F2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 29.24, - "z": 5.39 - }, - "F3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 29.24, - "z": 5.39 - }, - "F4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 29.24, - "z": 5.39 - }, - "F5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 29.24, - "z": 5.39 - }, - "F6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 29.24, - "z": 5.39 - }, - "F7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 29.24, - "z": 5.39 - }, - "F8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 29.24, - "z": 5.39 - }, - "F9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 29.24, - "z": 5.39 - }, - "G1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 20.24, - "z": 5.39 - }, - "G10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 20.24, - "z": 5.39 - }, - "G11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 20.24, - "z": 5.39 - }, - "G12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 20.24, - "z": 5.39 - }, - "G2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 20.24, - "z": 5.39 - }, - "G3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 20.24, - "z": 5.39 - }, - "G4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 20.24, - "z": 5.39 - }, - "G5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 20.24, - "z": 5.39 - }, - "G6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 20.24, - "z": 5.39 - }, - "G7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 20.24, - "z": 5.39 - }, - "G8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 20.24, - "z": 5.39 - }, - "G9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 20.24, - "z": 5.39 - }, - "H1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 11.24, - "z": 5.39 - }, - "H10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 11.24, - "z": 5.39 - }, - "H11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 11.24, - "z": 5.39 - }, - "H12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 11.24, - "z": 5.39 - }, - "H2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 11.24, - "z": 5.39 - }, - "H3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 11.24, - "z": 5.39 - }, - "H4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 11.24, - "z": 5.39 - }, - "H5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 11.24, - "z": 5.39 - }, - "H6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 11.24, - "z": 5.39 - }, - "H7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 11.24, - "z": 5.39 - }, - "H8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 11.24, - "z": 5.39 - }, - "H9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 11.24, - "z": 5.39 - } - } - } - }, - "status": "succeeded" - }, - { - "commandType": "loadLabware", - "notes": [], - "params": { - "displayName": "200µl filtertiprack", - "loadName": "opentrons_96_tiprack_300ul", - "location": { - "slotName": "11" - }, - "namespace": "opentrons", - "version": 1 - }, - "result": { - "definition": { - "allowedRoles": [], - "brand": { - "brand": "Opentrons", - "brandId": [], - "links": [ - "https://shop.opentrons.com/collections/opentrons-tips/products/opentrons-300ul-tips" - ] - }, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - }, - "dimensions": { - "xDimension": 127.76, - "yDimension": 85.48, - "zDimension": 64.49 - }, - "gripperOffsets": {}, - "groups": [ - { - "metadata": {}, - "wells": [ - "A1", - "A10", - "A11", - "A12", - "A2", - "A3", - "A4", - "A5", - "A6", - "A7", - "A8", - "A9", - "B1", - "B10", - "B11", - "B12", - "B2", - "B3", - "B4", - "B5", - "B6", - "B7", - "B8", - "B9", - "C1", - "C10", - "C11", - "C12", - "C2", - "C3", - "C4", - "C5", - "C6", - "C7", - "C8", - "C9", - "D1", - "D10", - "D11", - "D12", - "D2", - "D3", - "D4", - "D5", - "D6", - "D7", - "D8", - "D9", - "E1", - "E10", - "E11", - "E12", - "E2", - "E3", - "E4", - "E5", - "E6", - "E7", - "E8", - "E9", - "F1", - "F10", - "F11", - "F12", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - "F8", - "F9", - "G1", - "G10", - "G11", - "G12", - "G2", - "G3", - "G4", - "G5", - "G6", - "G7", - "G8", - "G9", - "H1", - "H10", - "H11", - "H12", - "H2", - "H3", - "H4", - "H5", - "H6", - "H7", - "H8", - "H9" - ] - } - ], - "metadata": { - "displayCategory": "tipRack", - "displayName": "Opentrons OT-2 96 Tip Rack 300 µL", - "displayVolumeUnits": "µL", - "tags": [] - }, - "namespace": "opentrons", - "ordering": [ - [ - "A1", - "B1", - "C1", - "D1", - "E1", - "F1", - "G1", - "H1" - ], - [ - "A10", - "B10", - "C10", - "D10", - "E10", - "F10", - "G10", - "H10" - ], - [ - "A11", - "B11", - "C11", - "D11", - "E11", - "F11", - "G11", - "H11" - ], - [ - "A12", - "B12", - "C12", - "D12", - "E12", - "F12", - "G12", - "H12" - ], - [ - "A2", - "B2", - "C2", - "D2", - "E2", - "F2", - "G2", - "H2" - ], - [ - "A3", - "B3", - "C3", - "D3", - "E3", - "F3", - "G3", - "H3" - ], - [ - "A4", - "B4", - "C4", - "D4", - "E4", - "F4", - "G4", - "H4" - ], - [ - "A5", - "B5", - "C5", - "D5", - "E5", - "F5", - "G5", - "H5" - ], - [ - "A6", - "B6", - "C6", - "D6", - "E6", - "F6", - "G6", - "H6" - ], - [ - "A7", - "B7", - "C7", - "D7", - "E7", - "F7", - "G7", - "H7" - ], - [ - "A8", - "B8", - "C8", - "D8", - "E8", - "F8", - "G8", - "H8" - ], - [ - "A9", - "B9", - "C9", - "D9", - "E9", - "F9", - "G9", - "H9" - ] - ], - "parameters": { - "format": "96Standard", - "isMagneticModuleCompatible": false, - "isTiprack": true, - "loadName": "opentrons_96_tiprack_300ul", - "tipLength": 59.3, - "tipOverlap": 7.47 - }, - "schemaVersion": 2, - "stackingOffsetWithLabware": {}, - "stackingOffsetWithModule": {}, - "version": 1, - "wells": { - "A1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 74.24, - "z": 5.39 - }, - "A10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 74.24, - "z": 5.39 - }, - "A11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 74.24, - "z": 5.39 - }, - "A12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 74.24, - "z": 5.39 - }, - "A2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 74.24, - "z": 5.39 - }, - "A3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 74.24, - "z": 5.39 - }, - "A4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 74.24, - "z": 5.39 - }, - "A5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 74.24, - "z": 5.39 - }, - "A6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 74.24, - "z": 5.39 - }, - "A7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 74.24, - "z": 5.39 - }, - "A8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 74.24, - "z": 5.39 - }, - "A9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 74.24, - "z": 5.39 - }, - "B1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 65.24, - "z": 5.39 - }, - "B10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 65.24, - "z": 5.39 - }, - "B11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 65.24, - "z": 5.39 - }, - "B12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 65.24, - "z": 5.39 - }, - "B2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 65.24, - "z": 5.39 - }, - "B3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 65.24, - "z": 5.39 - }, - "B4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 65.24, - "z": 5.39 - }, - "B5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 65.24, - "z": 5.39 - }, - "B6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 65.24, - "z": 5.39 - }, - "B7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 65.24, - "z": 5.39 - }, - "B8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 65.24, - "z": 5.39 - }, - "B9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 65.24, - "z": 5.39 - }, - "C1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 56.24, - "z": 5.39 - }, - "C10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 56.24, - "z": 5.39 - }, - "C11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 56.24, - "z": 5.39 - }, - "C12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 56.24, - "z": 5.39 - }, - "C2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 56.24, - "z": 5.39 - }, - "C3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 56.24, - "z": 5.39 - }, - "C4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 56.24, - "z": 5.39 - }, - "C5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 56.24, - "z": 5.39 - }, - "C6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 56.24, - "z": 5.39 - }, - "C7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 56.24, - "z": 5.39 - }, - "C8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 56.24, - "z": 5.39 - }, - "C9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 56.24, - "z": 5.39 - }, - "D1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 47.24, - "z": 5.39 - }, - "D10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 47.24, - "z": 5.39 - }, - "D11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 47.24, - "z": 5.39 - }, - "D12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 47.24, - "z": 5.39 - }, - "D2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 47.24, - "z": 5.39 - }, - "D3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 47.24, - "z": 5.39 - }, - "D4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 47.24, - "z": 5.39 - }, - "D5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 47.24, - "z": 5.39 - }, - "D6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 47.24, - "z": 5.39 - }, - "D7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 47.24, - "z": 5.39 - }, - "D8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 47.24, - "z": 5.39 - }, - "D9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 47.24, - "z": 5.39 - }, - "E1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 38.24, - "z": 5.39 - }, - "E10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 38.24, - "z": 5.39 - }, - "E11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 38.24, - "z": 5.39 - }, - "E12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 38.24, - "z": 5.39 - }, - "E2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 38.24, - "z": 5.39 - }, - "E3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 38.24, - "z": 5.39 - }, - "E4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 38.24, - "z": 5.39 - }, - "E5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 38.24, - "z": 5.39 - }, - "E6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 38.24, - "z": 5.39 - }, - "E7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 38.24, - "z": 5.39 - }, - "E8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 38.24, - "z": 5.39 - }, - "E9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 38.24, - "z": 5.39 - }, - "F1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 29.24, - "z": 5.39 - }, - "F10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 29.24, - "z": 5.39 - }, - "F11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 29.24, - "z": 5.39 - }, - "F12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 29.24, - "z": 5.39 - }, - "F2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 29.24, - "z": 5.39 - }, - "F3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 29.24, - "z": 5.39 - }, - "F4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 29.24, - "z": 5.39 - }, - "F5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 29.24, - "z": 5.39 - }, - "F6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 29.24, - "z": 5.39 - }, - "F7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 29.24, - "z": 5.39 - }, - "F8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 29.24, - "z": 5.39 - }, - "F9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 29.24, - "z": 5.39 - }, - "G1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 20.24, - "z": 5.39 - }, - "G10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 20.24, - "z": 5.39 - }, - "G11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 20.24, - "z": 5.39 - }, - "G12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 20.24, - "z": 5.39 - }, - "G2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 20.24, - "z": 5.39 - }, - "G3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 20.24, - "z": 5.39 - }, - "G4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 20.24, - "z": 5.39 - }, - "G5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 20.24, - "z": 5.39 - }, - "G6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 20.24, - "z": 5.39 - }, - "G7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 20.24, - "z": 5.39 - }, - "G8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 20.24, - "z": 5.39 - }, - "G9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 20.24, - "z": 5.39 - }, - "H1": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 14.38, - "y": 11.24, - "z": 5.39 - }, - "H10": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 95.38, - "y": 11.24, - "z": 5.39 - }, - "H11": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 104.38, - "y": 11.24, - "z": 5.39 - }, - "H12": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 113.38, - "y": 11.24, - "z": 5.39 - }, - "H2": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 23.38, - "y": 11.24, - "z": 5.39 - }, - "H3": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 32.38, - "y": 11.24, - "z": 5.39 - }, - "H4": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 41.38, - "y": 11.24, - "z": 5.39 - }, - "H5": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 50.38, - "y": 11.24, - "z": 5.39 - }, - "H6": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 59.38, - "y": 11.24, - "z": 5.39 - }, - "H7": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 68.38, - "y": 11.24, - "z": 5.39 - }, - "H8": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 77.38, - "y": 11.24, - "z": 5.39 - }, - "H9": { - "depth": 59.3, - "diameter": 5.23, - "shape": "circular", - "totalLiquidVolume": 300, - "x": 86.38, - "y": 11.24, - "z": 5.39 - } - } - } - }, - "status": "succeeded" - }, - { - "commandType": "loadLabware", - "notes": [], - "params": { - "displayName": "200µl filtertiprack", - "loadName": "opentrons_96_tiprack_20ul", - "location": { - "slotName": "4" - }, - "namespace": "opentrons", - "version": 1 - }, - "result": { - "definition": { - "allowedRoles": [], - "brand": { - "brand": "Opentrons", - "brandId": [], - "links": [ - "https://shop.opentrons.com/collections/opentrons-tips/products/opentrons-10ul-tips" - ] - }, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - }, - "dimensions": { - "xDimension": 127.76, - "yDimension": 85.48, - "zDimension": 64.69 - }, - "gripperOffsets": {}, - "groups": [ - { - "metadata": {}, - "wells": [ - "A1", - "A10", - "A11", - "A12", - "A2", - "A3", - "A4", - "A5", - "A6", - "A7", - "A8", - "A9", - "B1", - "B10", - "B11", - "B12", - "B2", - "B3", - "B4", - "B5", - "B6", - "B7", - "B8", - "B9", - "C1", - "C10", - "C11", - "C12", - "C2", - "C3", - "C4", - "C5", - "C6", - "C7", - "C8", - "C9", - "D1", - "D10", - "D11", - "D12", - "D2", - "D3", - "D4", - "D5", - "D6", - "D7", - "D8", - "D9", - "E1", - "E10", - "E11", - "E12", - "E2", - "E3", - "E4", - "E5", - "E6", - "E7", - "E8", - "E9", - "F1", - "F10", - "F11", - "F12", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - "F8", - "F9", - "G1", - "G10", - "G11", - "G12", - "G2", - "G3", - "G4", - "G5", - "G6", - "G7", - "G8", - "G9", - "H1", - "H10", - "H11", - "H12", - "H2", - "H3", - "H4", - "H5", - "H6", - "H7", - "H8", - "H9" - ] - } - ], - "metadata": { - "displayCategory": "tipRack", - "displayName": "Opentrons OT-2 96 Tip Rack 20 µL", - "displayVolumeUnits": "µL", - "tags": [] - }, - "namespace": "opentrons", - "ordering": [ - [ - "A1", - "B1", - "C1", - "D1", - "E1", - "F1", - "G1", - "H1" - ], - [ - "A10", - "B10", - "C10", - "D10", - "E10", - "F10", - "G10", - "H10" - ], - [ - "A11", - "B11", - "C11", - "D11", - "E11", - "F11", - "G11", - "H11" - ], - [ - "A12", - "B12", - "C12", - "D12", - "E12", - "F12", - "G12", - "H12" - ], - [ - "A2", - "B2", - "C2", - "D2", - "E2", - "F2", - "G2", - "H2" - ], - [ - "A3", - "B3", - "C3", - "D3", - "E3", - "F3", - "G3", - "H3" - ], - [ - "A4", - "B4", - "C4", - "D4", - "E4", - "F4", - "G4", - "H4" - ], - [ - "A5", - "B5", - "C5", - "D5", - "E5", - "F5", - "G5", - "H5" - ], - [ - "A6", - "B6", - "C6", - "D6", - "E6", - "F6", - "G6", - "H6" - ], - [ - "A7", - "B7", - "C7", - "D7", - "E7", - "F7", - "G7", - "H7" - ], - [ - "A8", - "B8", - "C8", - "D8", - "E8", - "F8", - "G8", - "H8" - ], - [ - "A9", - "B9", - "C9", - "D9", - "E9", - "F9", - "G9", - "H9" - ] - ], - "parameters": { - "format": "96Standard", - "isMagneticModuleCompatible": false, - "isTiprack": true, - "loadName": "opentrons_96_tiprack_20ul", - "tipLength": 39.2, - "tipOverlap": 8.25 - }, - "schemaVersion": 2, - "stackingOffsetWithLabware": {}, - "stackingOffsetWithModule": {}, - "version": 1, - "wells": { - "A1": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 14.38, - "y": 74.24, - "z": 25.49 - }, - "A10": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 95.38, - "y": 74.24, - "z": 25.49 - }, - "A11": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 104.38, - "y": 74.24, - "z": 25.49 - }, - "A12": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 113.38, - "y": 74.24, - "z": 25.49 - }, - "A2": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 23.38, - "y": 74.24, - "z": 25.49 - }, - "A3": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 32.38, - "y": 74.24, - "z": 25.49 - }, - "A4": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 41.38, - "y": 74.24, - "z": 25.49 - }, - "A5": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 50.38, - "y": 74.24, - "z": 25.49 - }, - "A6": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 59.38, - "y": 74.24, - "z": 25.49 - }, - "A7": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 68.38, - "y": 74.24, - "z": 25.49 - }, - "A8": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 77.38, - "y": 74.24, - "z": 25.49 - }, - "A9": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 86.38, - "y": 74.24, - "z": 25.49 - }, - "B1": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 14.38, - "y": 65.24, - "z": 25.49 - }, - "B10": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 95.38, - "y": 65.24, - "z": 25.49 - }, - "B11": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 104.38, - "y": 65.24, - "z": 25.49 - }, - "B12": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 113.38, - "y": 65.24, - "z": 25.49 - }, - "B2": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 23.38, - "y": 65.24, - "z": 25.49 - }, - "B3": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 32.38, - "y": 65.24, - "z": 25.49 - }, - "B4": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 41.38, - "y": 65.24, - "z": 25.49 - }, - "B5": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 50.38, - "y": 65.24, - "z": 25.49 - }, - "B6": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 59.38, - "y": 65.24, - "z": 25.49 - }, - "B7": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 68.38, - "y": 65.24, - "z": 25.49 - }, - "B8": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 77.38, - "y": 65.24, - "z": 25.49 - }, - "B9": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 86.38, - "y": 65.24, - "z": 25.49 - }, - "C1": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 14.38, - "y": 56.24, - "z": 25.49 - }, - "C10": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 95.38, - "y": 56.24, - "z": 25.49 - }, - "C11": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 104.38, - "y": 56.24, - "z": 25.49 - }, - "C12": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 113.38, - "y": 56.24, - "z": 25.49 - }, - "C2": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 23.38, - "y": 56.24, - "z": 25.49 - }, - "C3": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 32.38, - "y": 56.24, - "z": 25.49 - }, - "C4": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 41.38, - "y": 56.24, - "z": 25.49 - }, - "C5": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 50.38, - "y": 56.24, - "z": 25.49 - }, - "C6": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 59.38, - "y": 56.24, - "z": 25.49 - }, - "C7": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 68.38, - "y": 56.24, - "z": 25.49 - }, - "C8": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 77.38, - "y": 56.24, - "z": 25.49 - }, - "C9": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 86.38, - "y": 56.24, - "z": 25.49 - }, - "D1": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 14.38, - "y": 47.24, - "z": 25.49 - }, - "D10": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 95.38, - "y": 47.24, - "z": 25.49 - }, - "D11": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 104.38, - "y": 47.24, - "z": 25.49 - }, - "D12": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 113.38, - "y": 47.24, - "z": 25.49 - }, - "D2": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 23.38, - "y": 47.24, - "z": 25.49 - }, - "D3": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 32.38, - "y": 47.24, - "z": 25.49 - }, - "D4": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 41.38, - "y": 47.24, - "z": 25.49 - }, - "D5": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 50.38, - "y": 47.24, - "z": 25.49 - }, - "D6": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 59.38, - "y": 47.24, - "z": 25.49 - }, - "D7": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 68.38, - "y": 47.24, - "z": 25.49 - }, - "D8": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 77.38, - "y": 47.24, - "z": 25.49 - }, - "D9": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 86.38, - "y": 47.24, - "z": 25.49 - }, - "E1": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 14.38, - "y": 38.24, - "z": 25.49 - }, - "E10": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 95.38, - "y": 38.24, - "z": 25.49 - }, - "E11": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 104.38, - "y": 38.24, - "z": 25.49 - }, - "E12": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 113.38, - "y": 38.24, - "z": 25.49 - }, - "E2": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 23.38, - "y": 38.24, - "z": 25.49 - }, - "E3": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 32.38, - "y": 38.24, - "z": 25.49 - }, - "E4": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 41.38, - "y": 38.24, - "z": 25.49 - }, - "E5": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 50.38, - "y": 38.24, - "z": 25.49 - }, - "E6": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 59.38, - "y": 38.24, - "z": 25.49 - }, - "E7": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 68.38, - "y": 38.24, - "z": 25.49 - }, - "E8": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 77.38, - "y": 38.24, - "z": 25.49 - }, - "E9": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 86.38, - "y": 38.24, - "z": 25.49 - }, - "F1": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 14.38, - "y": 29.24, - "z": 25.49 - }, - "F10": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 95.38, - "y": 29.24, - "z": 25.49 - }, - "F11": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 104.38, - "y": 29.24, - "z": 25.49 - }, - "F12": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 113.38, - "y": 29.24, - "z": 25.49 - }, - "F2": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 23.38, - "y": 29.24, - "z": 25.49 - }, - "F3": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 32.38, - "y": 29.24, - "z": 25.49 - }, - "F4": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 41.38, - "y": 29.24, - "z": 25.49 - }, - "F5": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 50.38, - "y": 29.24, - "z": 25.49 - }, - "F6": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 59.38, - "y": 29.24, - "z": 25.49 - }, - "F7": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 68.38, - "y": 29.24, - "z": 25.49 - }, - "F8": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 77.38, - "y": 29.24, - "z": 25.49 - }, - "F9": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 86.38, - "y": 29.24, - "z": 25.49 - }, - "G1": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 14.38, - "y": 20.24, - "z": 25.49 - }, - "G10": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 95.38, - "y": 20.24, - "z": 25.49 - }, - "G11": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 104.38, - "y": 20.24, - "z": 25.49 - }, - "G12": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 113.38, - "y": 20.24, - "z": 25.49 - }, - "G2": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 23.38, - "y": 20.24, - "z": 25.49 - }, - "G3": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 32.38, - "y": 20.24, - "z": 25.49 - }, - "G4": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 41.38, - "y": 20.24, - "z": 25.49 - }, - "G5": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 50.38, - "y": 20.24, - "z": 25.49 - }, - "G6": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 59.38, - "y": 20.24, - "z": 25.49 - }, - "G7": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 68.38, - "y": 20.24, - "z": 25.49 - }, - "G8": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 77.38, - "y": 20.24, - "z": 25.49 - }, - "G9": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 86.38, - "y": 20.24, - "z": 25.49 - }, - "H1": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 14.38, - "y": 11.24, - "z": 25.49 - }, - "H10": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 95.38, - "y": 11.24, - "z": 25.49 - }, - "H11": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 104.38, - "y": 11.24, - "z": 25.49 - }, - "H12": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 113.38, - "y": 11.24, - "z": 25.49 - }, - "H2": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 23.38, - "y": 11.24, - "z": 25.49 - }, - "H3": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 32.38, - "y": 11.24, - "z": 25.49 - }, - "H4": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 41.38, - "y": 11.24, - "z": 25.49 - }, - "H5": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 50.38, - "y": 11.24, - "z": 25.49 - }, - "H6": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 59.38, - "y": 11.24, - "z": 25.49 - }, - "H7": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 68.38, - "y": 11.24, - "z": 25.49 - }, - "H8": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 77.38, - "y": 11.24, - "z": 25.49 - }, - "H9": { - "depth": 39.2, - "diameter": 3.27, - "shape": "circular", - "totalLiquidVolume": 20, - "x": 86.38, - "y": 11.24, - "z": 25.49 - } - } - } - }, - "status": "succeeded" - }, - { - "commandType": "loadPipette", - "notes": [], - "params": { - "mount": "left", - "pipetteName": "p300_multi_gen2" - }, - "result": {}, - "status": "succeeded" - }, - { - "commandType": "custom", - "notes": [], - "params": { - "legacyCommandText": "Setting Temperature Module temperature to 4.0 °C (rounded off to nearest integer)", - "legacyCommandType": "command.TEMPDECK_SET_TEMP" - }, - "result": {}, - "status": "succeeded" - }, - { - "commandType": "pickUpTip", - "notes": [], - "params": { - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "top" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "tipDiameter": 0, - "tipLength": 31.000000000000004, - "tipVolume": 20 - }, - "status": "succeeded" - }, - { - "commandType": "aspirate", - "notes": [], - "params": { - "flowRate": 50.0, - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "top" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "volume": 10.0 - }, - "status": "succeeded" - }, - { - "commandType": "dispense", - "notes": [], - "params": { - "flowRate": 150.0, - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "top" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "volume": 10.0 - }, - "status": "succeeded" - }, - { - "commandType": "aspirate", - "notes": [], - "params": { - "flowRate": 50.0, - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "top" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "volume": 10.0 - }, - "status": "succeeded" - }, - { - "commandType": "dispense", - "notes": [], - "params": { - "flowRate": 150.0, - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "top" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "volume": 10.0 - }, - "status": "succeeded" - }, - { - "commandType": "aspirate", - "notes": [], - "params": { - "flowRate": 50.0, - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "top" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "volume": 10.0 - }, - "status": "succeeded" - }, - { - "commandType": "dispense", - "notes": [], - "params": { - "flowRate": 150.0, - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "top" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "volume": 10.0 - }, - "status": "succeeded" - }, - { - "commandType": "aspirate", - "notes": [], - "params": { - "flowRate": 50.0, - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "top" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "volume": 10.0 - }, - "status": "succeeded" - }, - { - "commandType": "dispense", - "notes": [], - "params": { - "flowRate": 150.0, - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "top" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "volume": 10.0 - }, - "status": "succeeded" - }, - { - "commandType": "aspirate", - "notes": [], - "params": { - "flowRate": 50.0, - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "top" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "volume": 10.0 - }, - "status": "succeeded" - }, - { - "commandType": "dispense", - "notes": [], - "params": { - "flowRate": 150.0, - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "top" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "volume": 10.0 - }, - "status": "succeeded" - }, - { - "commandType": "aspirate", - "notes": [], - "params": { - "flowRate": 50.0, - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "top" - }, - "wellName": "A1" - }, - "result": { - "position": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "volume": 10.0 - }, - "status": "succeeded" - }, - { - "commandType": "custom", - "params": { - "legacyCommandText": "Air gap", - "legacyCommandType": "command.AIR_GAP" - }, - "status": "running" - }, - { - "commandType": "aspirate", - "params": { - "flowRate": 50.0, - "volume": 10.0, - "wellLocation": { - "offset": { - "x": 0, - "y": 0, - "z": 0 - }, - "origin": "top" - }, - "wellName": "A1" - }, - "status": "running" - } - ], - "config": { - "apiVersion": [ - 2, - 4 - ], - "protocolType": "python" - }, - "errors": [ - { - "detail": "AssertionError", - "errorCode": "4000", - "errorInfo": { - "args": "()", - "class": "AssertionError", - "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/protocol_engine.py\", line 442, in finish\n await exit_stack.aclose()\n\n File \"/usr/local/lib/python3.10/contextlib.py\", line 656, in aclose\n await self.__aexit__(None, None, None)\n\n File \"/usr/local/lib/python3.10/contextlib.py\", line 714, in __aexit__\n raise exc_details[1]\n\n File \"/usr/local/lib/python3.10/contextlib.py\", line 697, in __aexit__\n cb_suppress = await cb(*exc_details)\n\n File \"/usr/local/lib/python3.10/contextlib.py\", line 608, in _exit_wrapper\n await callback(*args, **kwds)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/plugins.py\", line 102, in stop\n await p.teardown()\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_runner/legacy_context_plugin.py\", line 112, in teardown\n await self._action_dispatching_task\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_runner/legacy_context_plugin.py\", line 160, in _dispatch_all_actions\n self.dispatch(action)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/plugins.py\", line 37, in dispatch\n return self._action_dispatcher.dispatch(action)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/actions/action_dispatcher.py\", line 30, in dispatch\n self._sink.handle_action(action)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/state/state.py\", line 207, in handle_action\n substore.handle_action(action)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/state/commands.py\", line 257, in handle_action\n self._state.command_history.set_command_running(running_command)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/state/command_history.py\", line 175, in set_command_running\n assert self.get_running_command() is None\n" - }, - "errorType": "PythonException", - "wrappedErrors": [] - } - ], - "files": [ - { - "name": "OT2_P300MLeft_MM_TM_2_4_Zymo.py", - "role": "main" - }, - { - "name": "cpx_4_tuberack_100ul.json", - "role": "labware" - }, - { - "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", - "role": "labware" - }, - { - "name": "opentrons_ot3_96_tiprack_200ul_rss.json", - "role": "labware" - }, - { - "name": "opentrons_ot3_96_tiprack_50ul_rss.json", - "role": "labware" - }, - { - "name": "sample_labware.json", - "role": "labware" - } - ], - "labware": [ - { - "definitionUri": "opentrons/opentrons_1_trash_1100ml_fixed/1", - "loadName": "opentrons_1_trash_1100ml_fixed", - "location": { - "slotName": "12" - } - }, - { - "definitionUri": "opentrons/nest_96_wellplate_2ml_deep/1", - "displayName": "deepwell plate", - "loadName": "nest_96_wellplate_2ml_deep", - "location": {} - }, - { - "definitionUri": "opentrons/opentrons_96_aluminumblock_nest_wellplate_100ul/1", - "loadName": "opentrons_96_aluminumblock_nest_wellplate_100ul", - "location": {} - }, - { - "definitionUri": "opentrons/nest_1_reservoir_195ml/1", - "displayName": "Liquid Waste", - "loadName": "nest_1_reservoir_195ml", - "location": { - "slotName": "9" - } - }, - { - "definitionUri": "opentrons/nest_12_reservoir_15ml/1", - "displayName": "reagent reservoir 2", - "loadName": "nest_12_reservoir_15ml", - "location": { - "slotName": "3" - } - }, - { - "definitionUri": "opentrons/nest_12_reservoir_15ml/1", - "displayName": "reagent reservoir 1", - "loadName": "nest_12_reservoir_15ml", - "location": { - "slotName": "2" - } - }, - { - "definitionUri": "opentrons/opentrons_96_tiprack_300ul/1", - "displayName": "200µl filtertiprack", - "loadName": "opentrons_96_tiprack_300ul", - "location": { - "slotName": "5" - } - }, - { - "definitionUri": "opentrons/opentrons_96_tiprack_300ul/1", - "displayName": "200µl filtertiprack", - "loadName": "opentrons_96_tiprack_300ul", - "location": { - "slotName": "7" - } - }, - { - "definitionUri": "opentrons/opentrons_96_tiprack_300ul/1", - "displayName": "200µl filtertiprack", - "loadName": "opentrons_96_tiprack_300ul", - "location": { - "slotName": "8" - } - }, - { - "definitionUri": "opentrons/opentrons_96_tiprack_300ul/1", - "displayName": "200µl filtertiprack", - "loadName": "opentrons_96_tiprack_300ul", - "location": { - "slotName": "10" - } - }, - { - "definitionUri": "opentrons/opentrons_96_tiprack_300ul/1", - "displayName": "200µl filtertiprack", - "loadName": "opentrons_96_tiprack_300ul", - "location": { - "slotName": "11" - } - }, - { - "definitionUri": "opentrons/opentrons_96_tiprack_20ul/1", - "displayName": "200µl filtertiprack", - "loadName": "opentrons_96_tiprack_20ul", - "location": { - "slotName": "4" - } - } - ], - "liquids": [], - "metadata": { - "apiLevel": "2.4", - "author": "Opentrons ", - "protocolName": "Zymo Direct-zol96 Magbead RNA" - }, - "modules": [ - { - "location": { - "slotName": "6" - }, - "model": "magneticModuleV2" - }, - { - "location": { - "slotName": "1" - }, - "model": "temperatureModuleV2" - } - ], - "pipettes": [ - { - "mount": "left", - "pipetteName": "p300_multi_gen2" - } - ], - "robotType": "OT-2 Standard", - "runTimeParameters": [] -} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[fb1d45057d][Flex_P1000_96_TC_2_16_PartialTipPickupColumn].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[8fcfd2ced0][Flex_S_v2_16_P1000_96_TC_PartialTipPickupColumn].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[fb1d45057d][Flex_P1000_96_TC_2_16_PartialTipPickupColumn].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[8fcfd2ced0][Flex_S_v2_16_P1000_96_TC_PartialTipPickupColumn].json index 866b69eace7..64660f2f085 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[fb1d45057d][Flex_P1000_96_TC_2_16_PartialTipPickupColumn].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[8fcfd2ced0][Flex_S_v2_16_P1000_96_TC_PartialTipPickupColumn].json @@ -2,12 +2,14 @@ "commands": [ { "commandType": "home", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "loadLabware", + "notes": [], "params": { "loadName": "opentrons_flex_96_tiprack_50ul", "location": { @@ -1159,6 +1161,7 @@ }, { "commandType": "loadPipette", + "notes": [], "params": { "mount": "left", "pipetteName": "p1000_96" @@ -1168,6 +1171,7 @@ }, { "commandType": "loadLabware", + "notes": [], "params": { "loadName": "nest_96_wellplate_200ul_flat", "location": { @@ -2328,6 +2332,7 @@ }, { "commandType": "loadLabware", + "notes": [], "params": { "loadName": "nest_96_wellplate_200ul_flat", "location": { @@ -3488,6 +3493,7 @@ }, { "commandType": "configureNozzleLayout", + "notes": [], "params": { "configurationParams": { "primaryNozzle": "A12", @@ -3499,6 +3505,7 @@ }, { "commandType": "pickUpTip", + "notes": [], "params": { "wellLocation": { "offset": { @@ -3524,6 +3531,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 50.0, @@ -3549,6 +3557,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "volume": 20.0, @@ -3574,6 +3583,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", + "notes": [], "params": { "addressableAreaName": "movableTrashA3", "alternateDropLocation": true, @@ -3596,6 +3606,7 @@ }, { "commandType": "dropTipInPlace", + "notes": [], "params": {}, "result": {}, "status": "succeeded" @@ -3611,7 +3622,7 @@ "errors": [], "files": [ { - "name": "Flex_P1000_96_TC_2_16_PartialTipPickupColumn.py", + "name": "Flex_S_v2_16_P1000_96_TC_PartialTipPickupColumn.py", "role": "main" }, { @@ -3667,5 +3678,6 @@ "pipetteName": "p1000_96" } ], - "robotType": "OT-3 Standard" + "robotType": "OT-3 Standard", + "runTimeParameters": [] } diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[7fa902bfa1][OT2_P300SG1_None_5_2_6_Gen1PipetteSimple].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[94913d2988][OT2_S_v3_P300SGen1_None_Gen1PipetteSimple].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[7fa902bfa1][OT2_P300SG1_None_5_2_6_Gen1PipetteSimple].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[94913d2988][OT2_S_v3_P300SGen1_None_Gen1PipetteSimple].json index b5d4180c5f4..92829c13eae 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[7fa902bfa1][OT2_P300SG1_None_5_2_6_Gen1PipetteSimple].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[94913d2988][OT2_S_v3_P300SGen1_None_Gen1PipetteSimple].json @@ -5772,7 +5772,7 @@ "errors": [], "files": [ { - "name": "OT2_P300SG1_None_5_2_6_Gen1PipetteSimple.json", + "name": "OT2_S_v3_P300SGen1_None_Gen1PipetteSimple.json", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[240b279ac3][OT2_P300S_Thermocycler_Moam_Error].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[9618a6623c][OT2_X_v2_11_P300S_TC1_TC2_ThermocyclerMoamError].json similarity index 98% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[240b279ac3][OT2_P300S_Thermocycler_Moam_Error].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[9618a6623c][OT2_X_v2_11_P300S_TC1_TC2_ThermocyclerMoamError].json index 35ec253ed42..bdace9efaf6 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[240b279ac3][OT2_P300S_Thermocycler_Moam_Error].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[9618a6623c][OT2_X_v2_11_P300S_TC1_TC2_ThermocyclerMoamError].json @@ -2680,7 +2680,7 @@ "errorInfo": { "args": "('thermocyclerModuleV2 in slot 7 prevents thermocyclerModuleV1 from using slot 7.',)", "class": "DeckConflictError", - "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"OT2_P300S_Thermocycler_Moam_Error.py\", line 19, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line 383, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/protocol_context.py\", line 814, in load_module\n module_core = self._core.load_module(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/legacy/legacy_protocol_core.py\", line 333, in load_module\n self._deck_layout[resolved_location] = geometry\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/legacy/deck.py\", line 186, in __setitem__\n deck_conflict.check(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/motion_planning/deck_conflict.py\", line 210, in check\n raise DeckConflictError(\n" + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"OT2_X_v2_11_P300S_TC1_TC2_ThermocyclerMoamError.py\", line 19, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line 383, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/protocol_context.py\", line 814, in load_module\n module_core = self._core.load_module(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/legacy/legacy_protocol_core.py\", line 333, in load_module\n self._deck_layout[resolved_location] = geometry\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/legacy/deck.py\", line 186, in __setitem__\n deck_conflict.check(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/motion_planning/deck_conflict.py\", line 210, in check\n raise DeckConflictError(\n" }, "errorType": "PythonException", "wrappedErrors": [] @@ -2690,7 +2690,7 @@ ], "files": [ { - "name": "OT2_P300S_Thermocycler_Moam_Error.py", + "name": "OT2_X_v2_11_P300S_TC1_TC2_ThermocyclerMoamError.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[88c6605849][Flex_None_None_TC_2_16_verifyThermocyclerLoadedSlots].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[973fa979e6][Flex_S_v2_16_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots].json similarity index 95% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[88c6605849][Flex_None_None_TC_2_16_verifyThermocyclerLoadedSlots].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[973fa979e6][Flex_S_v2_16_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots].json index 68e957910ee..7ce33092ad3 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[88c6605849][Flex_None_None_TC_2_16_verifyThermocyclerLoadedSlots].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[973fa979e6][Flex_S_v2_16_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots].json @@ -137,7 +137,7 @@ "errorInfo": { "args": "()", "class": "AssertionError", - "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_None_None_TC_2_16_verifyThermocyclerLoadedSlots.py\", line 13, in run\n" + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_S_v2_16_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots.py\", line 13, in run\n" }, "errorType": "PythonException", "wrappedErrors": [] @@ -147,7 +147,7 @@ ], "files": [ { - "name": "Flex_None_None_TC_2_16_verifyThermocyclerLoadedSlots.py", + "name": "Flex_S_v2_16_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[5eb46a4f85][Flex_P1000_96_GRIPPER_2_16_AnalysisError_DropLabwareIntoTrashBin].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[9e56ee92f6][Flex_X_v2_16_P1000_96_GRIP_DropLabwareIntoTrashBin].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[5eb46a4f85][Flex_P1000_96_GRIPPER_2_16_AnalysisError_DropLabwareIntoTrashBin].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[9e56ee92f6][Flex_X_v2_16_P1000_96_GRIP_DropLabwareIntoTrashBin].json index f72a3066d6a..6916e6613a3 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[5eb46a4f85][Flex_P1000_96_GRIPPER_2_16_AnalysisError_DropLabwareIntoTrashBin].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[9e56ee92f6][Flex_X_v2_16_P1000_96_GRIP_DropLabwareIntoTrashBin].json @@ -1261,7 +1261,7 @@ "notes": [], "params": { "addressableAreaName": "movableTrashC3", - "alternateDropLocation": false, + "alternateDropLocation": true, "forceDirect": false, "ignoreTipConfiguration": true, "offset": { @@ -1272,7 +1272,7 @@ }, "result": { "position": { - "x": 434.25, + "x": 466.25, "y": 150.0, "z": 40.0 } @@ -1339,7 +1339,7 @@ ], "files": [ { - "name": "Flex_P1000_96_GRIPPER_2_16_AnalysisError_DropLabwareIntoTrashBin.py", + "name": "Flex_X_v2_16_P1000_96_GRIP_DropLabwareIntoTrashBin.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a550135de6][Flex_None_None_2_16_AnalysisError_TrashBinInStagingAreaCol3].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a01a35c14a][Flex_X_v2_16_NO_PIPETTES_TrashBinInStagingAreaCol3].json similarity index 98% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a550135de6][Flex_None_None_2_16_AnalysisError_TrashBinInStagingAreaCol3].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a01a35c14a][Flex_X_v2_16_NO_PIPETTES_TrashBinInStagingAreaCol3].json index 9030ad7192c..4670580f316 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a550135de6][Flex_None_None_2_16_AnalysisError_TrashBinInStagingAreaCol3].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a01a35c14a][Flex_X_v2_16_NO_PIPETTES_TrashBinInStagingAreaCol3].json @@ -121,7 +121,7 @@ ], "files": [ { - "name": "Flex_None_None_2_16_AnalysisError_TrashBinInStagingAreaCol3.py", + "name": "Flex_X_v2_16_NO_PIPETTES_TrashBinInStagingAreaCol3.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a06502b2dc][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_description].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a06502b2dc][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_description].json new file mode 100644 index 00000000000..fd0394ca385 --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a06502b2dc][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_description].json @@ -0,0 +1,74 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + } + ], + "config": { + "apiVersion": [ + 2, + 18 + ], + "protocolType": "python" + }, + "errors": [ + { + "detail": "ParameterNameError [line 84]: Description must be a string and at most 100 characters.", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ExceptionInProtocolError", + "wrappedErrors": [ + { + "detail": "opentrons.protocols.parameters.types.ParameterNameError: Description must be a string and at most 100 characters.", + "errorCode": "4000", + "errorInfo": { + "args": "('Description must be a string and at most 100 characters.',)", + "class": "ParameterNameError", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 80, in _parse_and_set_parameters\n exec(\"add_parameters(__param_context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_description.py\", line 84, in add_parameters\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/_parameter_context.py\", line 152, in add_str\n parameter = parameter_definition.create_str_parameter(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 241, in create_str_parameter\n return ParameterDefinition(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 58, in __init__\n self._description = validation.ensure_description(description)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/validation.py\", line 60, in ensure_description\n raise ParameterNameError(\n" + }, + "errorType": "PythonException", + "wrappedErrors": [] + } + ] + } + ], + "files": [ + { + "name": "Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_description.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "protocolName": "Description Too Long 2.18" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-3 Standard", + "runTimeParameters": [] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[d577930518][Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoModulesNoFixtures].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a08c261369][Flex_S_v2_16_P1000_96_GRIP_DeckConfiguration1NoModulesNoFixtures].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[d577930518][Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoModulesNoFixtures].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a08c261369][Flex_S_v2_16_P1000_96_GRIP_DeckConfiguration1NoModulesNoFixtures].json index 297b7cf8878..7869a86e776 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[d577930518][Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoModulesNoFixtures].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a08c261369][Flex_S_v2_16_P1000_96_GRIP_DeckConfiguration1NoModulesNoFixtures].json @@ -8614,7 +8614,7 @@ "errors": [], "files": [ { - "name": "Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoModulesNoFixtures.py", + "name": "Flex_S_v2_16_P1000_96_GRIP_DeckConfiguration1NoModulesNoFixtures.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[20cefcac62][OT2_P300M_P20S_TC_HS_TM_2_13_SmokeTestV3].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a66d700ed6][OT2_S_v2_13_P300M_P20S_HS_TC_TM_SmokeTestV3].json similarity index 95% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[20cefcac62][OT2_P300M_P20S_TC_HS_TM_2_13_SmokeTestV3].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a66d700ed6][OT2_S_v2_13_P300M_P20S_HS_TC_TM_SmokeTestV3].json index 2f1e2018f18..dc96969c9c7 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[20cefcac62][OT2_P300M_P20S_TC_HS_TM_2_13_SmokeTestV3].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a66d700ed6][OT2_S_v2_13_P300M_P20S_HS_TC_TM_SmokeTestV3].json @@ -11849,18 +11849,525 @@ }, "status": "succeeded" }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 7.56, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A11" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Delaying for 0 minutes and 3.0 seconds", + "legacyCommandType": "command.DELAY" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 7.56, + "volume": 5.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "H11" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 5.0 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to E12 of logo destination on 2", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Moving to E11 of logo destination on 2", + "legacyCommandType": "command.MOVE_TO" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "blowout", + "notes": [], + "params": { + "flowRate": 7.56, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "E11" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Touching tip", + "legacyCommandType": "command.TOUCH_TIP" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "dropTip", + "notes": [], + "params": { + "alternateDropLocation": false, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "default" + }, + "wellName": "C1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Waiting for Temperature Module to reach temperature 25.0 °C (rounded off to nearest integer)", + "legacyCommandType": "command.TEMPDECK_AWAIT_TEMP" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Setting Heater-Shaker to Shake at 466 RPM and waiting until reached", + "legacyCommandType": "command.HEATER_SHAKER_SET_AND_WAIT_FOR_SHAKE_SPEED" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Delaying for 0 minutes and 5.0 seconds", + "legacyCommandType": "command.DELAY" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Setting Target Temperature of Heater-Shaker to 38 °C", + "legacyCommandType": "command.HEATER_SHAKER_SET_TARGET_TEMPERATURE" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Waiting for Heater-Shaker to reach target temperature", + "legacyCommandType": "command.HEATER_SHAKER_WAIT_FOR_TEMPERATURE" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Opening Thermocycler lid", + "legacyCommandType": "command.THERMOCYCLER_OPEN" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Closing Thermocycler lid", + "legacyCommandType": "command.THERMOCYCLER_CLOSE" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Setting Thermocycler lid temperature to 38.0 °C", + "legacyCommandType": "command.THERMOCYCLER_SET_LID_TEMP" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Setting Thermocycler well block temperature to 28.0 °C with a hold time of 5 seconds", + "legacyCommandType": "command.THERMOCYCLER_SET_BLOCK_TEMP" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Deactivating Thermocycler well block heating", + "legacyCommandType": "command.THERMOCYCLER_DEACTIVATE_BLOCK" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Deactivating Thermocycler lid heating", + "legacyCommandType": "command.THERMOCYCLER_DEACTIVATE_LID" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Opening Thermocycler lid", + "legacyCommandType": "command.THERMOCYCLER_OPEN" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Deactivating Shaker", + "legacyCommandType": "command.HEATER_SHAKER_DEACTIVATE_SHAKER" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "waitForResume", + "notes": [], + "params": { + "message": "This is a pause" + }, + "status": "succeeded" + }, + { + "commandType": "pickUpTip", + "notes": [], + "params": { + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "D1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "tipDiameter": 0, + "tipLength": 30.950000000000003, + "tipVolume": 20 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 7.56, + "volume": 15.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 15.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 7.56, + "volume": 15.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 15.0 + }, + "status": "succeeded" + }, + { + "commandType": "dropTip", + "notes": [], + "params": { + "alternateDropLocation": false, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "default" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "pickUpTip", + "notes": [], + "params": { + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "tipDiameter": 0, + "tipLength": 51.099999999999994, + "tipVolume": 300 + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 94.0, + "volume": 50.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 50.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 94.0, + "volume": 50.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 50.0 + }, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Setting Heater-Shaker to Shake at 350 RPM and waiting until reached", + "legacyCommandType": "command.HEATER_SHAKER_SET_AND_WAIT_FOR_SHAKE_SPEED" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Delaying for 0 minutes and 5.0 seconds", + "legacyCommandType": "command.DELAY" + }, + "result": {}, + "status": "succeeded" + }, { "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "Deactivating Shaker", + "legacyCommandType": "command.HEATER_SHAKER_DEACTIVATE_SHAKER" + }, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "pickUpTip", + "notes": [], "params": { - "legacyCommandText": "Air gap", - "legacyCommandType": "command.AIR_GAP" + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "E1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "tipDiameter": 0, + "tipLength": 30.950000000000003, + "tipVolume": 20 }, - "status": "running" + "status": "succeeded" }, { "commandType": "aspirate", + "notes": [], "params": { - "flowRate": 7.56, + "flowRate": 15.12, "volume": 10.0, "wellLocation": { "offset": { @@ -11870,9 +12377,143 @@ }, "origin": "top" }, - "wellName": "A11" + "wellName": "A2" }, - "status": "running" + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 11.34, + "volume": 10.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "B2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 10.0 + }, + "status": "succeeded" + }, + { + "commandType": "dropTip", + "notes": [], + "params": { + "alternateDropLocation": false, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "default" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" + }, + { + "commandType": "aspirate", + "notes": [], + "params": { + "flowRate": 94.0, + "volume": 75.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A2" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 75.0 + }, + "status": "succeeded" + }, + { + "commandType": "dispense", + "notes": [], + "params": { + "flowRate": 94.0, + "volume": 60.0, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "top" + }, + "wellName": "A6" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "volume": 60.0 + }, + "status": "succeeded" + }, + { + "commandType": "dropTip", + "notes": [], + "params": { + "alternateDropLocation": false, + "wellLocation": { + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "origin": "default" + }, + "wellName": "A1" + }, + "result": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "status": "succeeded" } ], "config": { @@ -11882,22 +12523,10 @@ ], "protocolType": "python" }, - "errors": [ - { - "detail": "AssertionError", - "errorCode": "4000", - "errorInfo": { - "args": "()", - "class": "AssertionError", - "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/protocol_engine.py\", line 442, in finish\n await exit_stack.aclose()\n\n File \"/usr/local/lib/python3.10/contextlib.py\", line 656, in aclose\n await self.__aexit__(None, None, None)\n\n File \"/usr/local/lib/python3.10/contextlib.py\", line 714, in __aexit__\n raise exc_details[1]\n\n File \"/usr/local/lib/python3.10/contextlib.py\", line 697, in __aexit__\n cb_suppress = await cb(*exc_details)\n\n File \"/usr/local/lib/python3.10/contextlib.py\", line 608, in _exit_wrapper\n await callback(*args, **kwds)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/plugins.py\", line 102, in stop\n await p.teardown()\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_runner/legacy_context_plugin.py\", line 112, in teardown\n await self._action_dispatching_task\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_runner/legacy_context_plugin.py\", line 160, in _dispatch_all_actions\n self.dispatch(action)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/plugins.py\", line 37, in dispatch\n return self._action_dispatcher.dispatch(action)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/actions/action_dispatcher.py\", line 30, in dispatch\n self._sink.handle_action(action)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/state/state.py\", line 207, in handle_action\n substore.handle_action(action)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/state/commands.py\", line 257, in handle_action\n self._state.command_history.set_command_running(running_command)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/state/command_history.py\", line 175, in set_command_running\n assert self.get_running_command() is None\n" - }, - "errorType": "PythonException", - "wrappedErrors": [] - } - ], + "errors": [], "files": [ { - "name": "OT2_P300M_P20S_TC_HS_TM_2_13_SmokeTestV3.py", + "name": "OT2_S_v2_13_P300M_P20S_HS_TC_TM_SmokeTestV3.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[dc8ac87114][Flex_None_None_2_16_AnalysisError_AccessToFixedTrashProp].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a9557d762c][Flex_X_v2_16_NO_PIPETTES_AccessToFixedTrashProp].json similarity index 78% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[dc8ac87114][Flex_None_None_2_16_AnalysisError_AccessToFixedTrashProp].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a9557d762c][Flex_X_v2_16_NO_PIPETTES_AccessToFixedTrashProp].json index 257a29f5a73..246e3a98216 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[dc8ac87114][Flex_None_None_2_16_AnalysisError_AccessToFixedTrashProp].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[a9557d762c][Flex_X_v2_16_NO_PIPETTES_AccessToFixedTrashProp].json @@ -28,7 +28,7 @@ "errorInfo": { "args": "('Fixed Trash is not supported on Flex protocols in API Version 2.16 and above.',)", "class": "APIVersionError", - "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_None_None_2_16_AnalysisError_AccessToFixedTrashProp.py\", line 15, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line 383, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/protocol_context.py\", line 1118, in fixed_trash\n raise APIVersionError(\n" + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_X_v2_16_NO_PIPETTES_AccessToFixedTrashProp.py\", line 15, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line 383, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/protocol_context.py\", line 1118, in fixed_trash\n raise APIVersionError(\n" }, "errorType": "PythonException", "wrappedErrors": [] @@ -38,7 +38,7 @@ ], "files": [ { - "name": "Flex_None_None_2_16_AnalysisError_AccessToFixedTrashProp.py", + "name": "Flex_X_v2_16_NO_PIPETTES_AccessToFixedTrashProp.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[3758150ec1][Flex_P1000_96_None_2_15_ABR5_6_IDT_xGen_EZ_96x_Head_PART_I_III_ABR].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[ac886d7768][Flex_S_v2_15_P1000_96_GRIP_HS_MB_TC_TM_IDTXgen96Part1to3].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[3758150ec1][Flex_P1000_96_None_2_15_ABR5_6_IDT_xGen_EZ_96x_Head_PART_I_III_ABR].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[ac886d7768][Flex_S_v2_15_P1000_96_GRIP_HS_MB_TC_TM_IDTXgen96Part1to3].json index 3041ec1374d..043fbd6f36c 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[3758150ec1][Flex_P1000_96_None_2_15_ABR5_6_IDT_xGen_EZ_96x_Head_PART_I_III_ABR].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[ac886d7768][Flex_S_v2_15_P1000_96_GRIP_HS_MB_TC_TM_IDTXgen96Part1to3].json @@ -11032,7 +11032,7 @@ ], "files": [ { - "name": "Flex_P1000_96_None_2_15_ABR5_6_IDT_xGen_EZ_96x_Head_PART_I_III_ABR.py", + "name": "Flex_S_v2_15_P1000_96_GRIP_HS_MB_TC_TM_IDTXgen96Part1to3.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[af0b02a5db][OT2_P300M_P20S_HS_6_1_Smoke620release].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[ad627dcedf][OT2_S_v6_P300M_P20S_HS_Smoke620release].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[af0b02a5db][OT2_P300M_P20S_HS_6_1_Smoke620release].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[ad627dcedf][OT2_S_v6_P300M_P20S_HS_Smoke620release].json index 881c6ce7e45..537d3e68d3d 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[af0b02a5db][OT2_P300M_P20S_HS_6_1_Smoke620release].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[ad627dcedf][OT2_S_v6_P300M_P20S_HS_Smoke620release].json @@ -8469,7 +8469,7 @@ "errors": [], "files": [ { - "name": "OT2_P300M_P20S_HS_6_1_Smoke620release.json", + "name": "OT2_S_v6_P300M_P20S_HS_Smoke620release.json", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[cf80c979bd][Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLid].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[adc0621263][Flex_X_v2_16_P1000_96_TC_pipetteCollisionWithThermocyclerLid].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[cf80c979bd][Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLid].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[adc0621263][Flex_X_v2_16_P1000_96_TC_pipetteCollisionWithThermocyclerLid].json index ea4fd2cda9b..ad5e91cee31 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[cf80c979bd][Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLid].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[adc0621263][Flex_X_v2_16_P1000_96_TC_pipetteCollisionWithThermocyclerLid].json @@ -6091,7 +6091,7 @@ ], "files": [ { - "name": "Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLid.py", + "name": "Flex_X_v2_16_P1000_96_TC_pipetteCollisionWithThermocyclerLid.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[ad845b131b][Flex_P1000_96_TC_2_16_AnalysisError_PartialTipPickupTryToReturnTip].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[b0ce7dde5d][Flex_X_v2_16_P1000_96_TC_PartialTipPickupTryToReturnTip].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[ad845b131b][Flex_P1000_96_TC_2_16_AnalysisError_PartialTipPickupTryToReturnTip].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[b0ce7dde5d][Flex_X_v2_16_P1000_96_TC_PartialTipPickupTryToReturnTip].json index 8185dcf40a5..58f383ed1ba 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[ad845b131b][Flex_P1000_96_TC_2_16_AnalysisError_PartialTipPickupTryToReturnTip].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[b0ce7dde5d][Flex_X_v2_16_P1000_96_TC_PartialTipPickupTryToReturnTip].json @@ -2,12 +2,14 @@ "commands": [ { "commandType": "home", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "loadLabware", + "notes": [], "params": { "loadName": "opentrons_flex_96_tiprack_50ul", "location": { @@ -1159,6 +1161,7 @@ }, { "commandType": "loadPipette", + "notes": [], "params": { "mount": "left", "pipetteName": "p1000_96" @@ -1168,6 +1171,7 @@ }, { "commandType": "loadLabware", + "notes": [], "params": { "loadName": "nest_96_wellplate_200ul_flat", "location": { @@ -2328,6 +2332,7 @@ }, { "commandType": "loadLabware", + "notes": [], "params": { "loadName": "nest_96_wellplate_200ul_flat", "location": { @@ -3488,6 +3493,7 @@ }, { "commandType": "configureNozzleLayout", + "notes": [], "params": { "configurationParams": { "primaryNozzle": "A12", @@ -3499,6 +3505,7 @@ }, { "commandType": "pickUpTip", + "notes": [], "params": { "wellLocation": { "offset": { @@ -3524,6 +3531,7 @@ }, { "commandType": "aspirate", + "notes": [], "params": { "flowRate": 160.0, "volume": 50.0, @@ -3549,6 +3557,7 @@ }, { "commandType": "dispense", + "notes": [], "params": { "flowRate": 160.0, "volume": 20.0, @@ -3599,7 +3608,7 @@ ], "files": [ { - "name": "Flex_P1000_96_TC_2_16_AnalysisError_PartialTipPickupTryToReturnTip.py", + "name": "Flex_X_v2_16_P1000_96_TC_PartialTipPickupTryToReturnTip.py", "role": "main" }, { @@ -3655,5 +3664,6 @@ "pipetteName": "p1000_96" } ], - "robotType": "OT-3 Standard" + "robotType": "OT-3 Standard", + "runTimeParameters": [] } diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[b806f07be9][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_choice_value].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[b806f07be9][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_choice_value].json new file mode 100644 index 00000000000..04e274d2ef4 --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[b806f07be9][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_choice_value].json @@ -0,0 +1,74 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + } + ], + "config": { + "apiVersion": [ + 2, + 18 + ], + "protocolType": "python" + }, + "errors": [ + { + "detail": "ParameterDefinitionError [line 62]: All choices provided must be of type 'str'", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ExceptionInProtocolError", + "wrappedErrors": [ + { + "detail": "opentrons.protocols.parameters.types.ParameterDefinitionError: All choices provided must be of type 'str'", + "errorCode": "4000", + "errorInfo": { + "args": "(\"All choices provided must be of type 'str'\",)", + "class": "ParameterDefinitionError", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 80, in _parse_and_set_parameters\n exec(\"add_parameters(__param_context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_choice_value.py\", line 62, in add_parameters\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/_parameter_context.py\", line 152, in add_str\n parameter = parameter_definition.create_str_parameter(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 241, in create_str_parameter\n return ParameterDefinition(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 73, in __init__\n validation.validate_options(default, minimum, maximum, choices, parameter_type)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/validation.py\", line 264, in validate_options\n _validate_choices(minimum, maximum, choices, parameter_type)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/validation.py\", line 191, in _validate_choices\n raise ParameterDefinitionError(\n" + }, + "errorType": "PythonException", + "wrappedErrors": [] + } + ] + } + ], + "files": [ + { + "name": "Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_choice_value.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "protocolName": "Description Too Long 2.18" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-3 Standard", + "runTimeParameters": [] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[2dbe35fede][Flex_P1000SRight_None_2_15_ABR_Simple_Normalize_Long_Right].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[baf79d9b4a][Flex_S_v2_15_P1000S_None_SimpleNormalizeLongRight].json similarity index 96% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[2dbe35fede][Flex_P1000SRight_None_2_15_ABR_Simple_Normalize_Long_Right].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[baf79d9b4a][Flex_S_v2_15_P1000S_None_SimpleNormalizeLongRight].json index 72e4dc6770f..736af3bb4ce 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[2dbe35fede][Flex_P1000SRight_None_2_15_ABR_Simple_Normalize_Long_Right].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[baf79d9b4a][Flex_S_v2_15_P1000S_None_SimpleNormalizeLongRight].json @@ -10753,7 +10753,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -10779,7 +10779,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -10805,7 +10805,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -10831,7 +10831,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -10857,7 +10857,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -10883,7 +10883,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -10909,7 +10909,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -10935,7 +10935,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -10961,7 +10961,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -10987,7 +10987,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -11013,7 +11013,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -11039,7 +11039,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -11065,7 +11065,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -11091,7 +11091,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -11117,7 +11117,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -11143,7 +11143,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -11169,7 +11169,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -11195,7 +11195,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -11221,7 +11221,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -11247,7 +11247,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -11273,7 +11273,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -11299,7 +11299,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -11325,7 +11325,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -11351,7 +11351,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -11377,7 +11377,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -11403,7 +11403,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -11429,7 +11429,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -11455,7 +11455,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -11481,7 +11481,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -11507,7 +11507,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -11533,7 +11533,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -11559,7 +11559,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -11585,7 +11585,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -11611,7 +11611,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -11637,7 +11637,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -11663,7 +11663,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -11689,7 +11689,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -11715,7 +11715,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -11741,7 +11741,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -11767,7 +11767,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -11793,7 +11793,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -11819,7 +11819,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -11845,7 +11845,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -11871,7 +11871,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -11897,7 +11897,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11923,7 +11923,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11949,7 +11949,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -11975,7 +11975,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -12001,7 +12001,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -12027,7 +12027,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -12053,7 +12053,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -12079,7 +12079,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -12105,7 +12105,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -12131,7 +12131,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -12157,7 +12157,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -12183,7 +12183,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -12209,7 +12209,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -12235,7 +12235,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -12261,7 +12261,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -12287,7 +12287,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -12313,7 +12313,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -12339,7 +12339,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -12365,7 +12365,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -12391,7 +12391,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -12417,7 +12417,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -12443,7 +12443,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -12469,7 +12469,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -12495,7 +12495,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -12521,7 +12521,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -12547,7 +12547,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -12573,7 +12573,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -12599,7 +12599,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -12625,7 +12625,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -12651,7 +12651,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -12677,7 +12677,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -12703,7 +12703,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -12729,7 +12729,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -12755,7 +12755,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -12781,7 +12781,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -12807,7 +12807,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -12833,7 +12833,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -12859,7 +12859,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -12885,7 +12885,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -12911,7 +12911,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -12937,7 +12937,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -12963,7 +12963,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -12989,7 +12989,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -13015,7 +13015,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -13041,7 +13041,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -13067,7 +13067,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -13093,7 +13093,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -13119,7 +13119,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -13145,7 +13145,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -13171,7 +13171,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -13197,7 +13197,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -13223,7 +13223,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -13249,7 +13249,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -13275,7 +13275,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -13301,7 +13301,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -13327,7 +13327,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -13353,7 +13353,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -13379,7 +13379,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -13405,7 +13405,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -13431,7 +13431,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -13457,7 +13457,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -13483,7 +13483,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -13509,7 +13509,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -13535,7 +13535,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -13561,7 +13561,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -13587,7 +13587,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -13613,7 +13613,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -13639,7 +13639,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -13665,7 +13665,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -13691,7 +13691,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -13717,7 +13717,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -13743,7 +13743,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -13769,7 +13769,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -13795,7 +13795,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -13821,7 +13821,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -13847,7 +13847,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -13873,7 +13873,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -13899,7 +13899,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -13925,7 +13925,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -13951,7 +13951,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -13977,7 +13977,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -14003,7 +14003,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -14029,7 +14029,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -14055,7 +14055,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -14081,7 +14081,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -14107,7 +14107,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -14133,7 +14133,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -14159,7 +14159,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -14185,7 +14185,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -14211,7 +14211,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -14237,7 +14237,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -14263,7 +14263,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -14289,7 +14289,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -14315,7 +14315,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -14341,7 +14341,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -14367,7 +14367,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -14393,7 +14393,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -14419,7 +14419,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -14445,7 +14445,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -14471,7 +14471,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -14497,7 +14497,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -14523,7 +14523,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -14549,7 +14549,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -14575,7 +14575,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -14601,7 +14601,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -14627,7 +14627,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -14653,7 +14653,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -14679,7 +14679,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -14705,7 +14705,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -14731,7 +14731,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -14757,7 +14757,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -14783,7 +14783,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -14809,7 +14809,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -14835,7 +14835,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -14861,7 +14861,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -14887,7 +14887,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -14913,7 +14913,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -14939,7 +14939,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -14965,7 +14965,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -14991,7 +14991,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -15017,7 +15017,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -15043,7 +15043,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -15069,7 +15069,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -15095,7 +15095,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -15121,7 +15121,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -15147,7 +15147,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -15173,7 +15173,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -15199,7 +15199,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -15225,7 +15225,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -15251,7 +15251,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -15277,7 +15277,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -15303,7 +15303,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -15329,7 +15329,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -15355,7 +15355,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -15381,7 +15381,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -15407,7 +15407,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -15433,7 +15433,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -15459,7 +15459,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -15485,7 +15485,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -15511,7 +15511,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -15537,7 +15537,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -15563,7 +15563,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -15589,7 +15589,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -15615,7 +15615,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -15641,7 +15641,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -15667,7 +15667,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -15773,7 +15773,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -15799,7 +15799,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -15875,7 +15875,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -15901,7 +15901,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -15977,7 +15977,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -16003,7 +16003,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -16079,7 +16079,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -16105,7 +16105,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -16181,7 +16181,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -16207,7 +16207,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -16283,7 +16283,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -16309,7 +16309,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -16385,7 +16385,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -16411,7 +16411,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -16487,7 +16487,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -16513,7 +16513,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -16589,7 +16589,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -16615,7 +16615,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -16691,7 +16691,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -16717,7 +16717,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -16793,7 +16793,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -16819,7 +16819,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -16895,7 +16895,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -16921,7 +16921,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -16997,7 +16997,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -17023,7 +17023,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -17099,7 +17099,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -17125,7 +17125,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -17201,7 +17201,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -17227,7 +17227,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -17303,7 +17303,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -17329,7 +17329,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -17405,7 +17405,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -17431,7 +17431,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -17507,7 +17507,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -17533,7 +17533,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -17609,7 +17609,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -17635,7 +17635,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -17711,7 +17711,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -17737,7 +17737,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -17813,7 +17813,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -17839,7 +17839,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -17915,7 +17915,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -17941,7 +17941,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -18017,7 +18017,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -18043,7 +18043,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -18119,7 +18119,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -18145,7 +18145,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -18221,7 +18221,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -18247,7 +18247,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -18323,7 +18323,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -18349,7 +18349,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -18425,7 +18425,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -18451,7 +18451,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -18527,7 +18527,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -18553,7 +18553,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -18629,7 +18629,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -18655,7 +18655,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -18731,7 +18731,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -18757,7 +18757,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -18833,7 +18833,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -18859,7 +18859,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -18935,7 +18935,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -18961,7 +18961,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -19037,7 +19037,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -19063,7 +19063,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -19139,7 +19139,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -19165,7 +19165,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -19241,7 +19241,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -19267,7 +19267,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -19343,7 +19343,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -19369,7 +19369,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -19445,7 +19445,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -19471,7 +19471,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -19547,7 +19547,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -19573,7 +19573,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -19649,7 +19649,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -19675,7 +19675,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -19751,7 +19751,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -19777,7 +19777,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -19853,7 +19853,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -19879,7 +19879,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -19955,7 +19955,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -19981,7 +19981,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -20057,7 +20057,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -20083,7 +20083,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -20159,7 +20159,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -20185,7 +20185,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -20261,7 +20261,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -20287,7 +20287,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -20363,7 +20363,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -20389,7 +20389,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -20465,7 +20465,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -20491,7 +20491,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -20567,7 +20567,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -20593,7 +20593,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -20669,7 +20669,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -20695,7 +20695,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -20771,7 +20771,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -20797,7 +20797,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -20873,7 +20873,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -20899,7 +20899,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -20975,7 +20975,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21001,7 +21001,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -21077,7 +21077,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -21103,7 +21103,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -21179,7 +21179,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -21205,7 +21205,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -21281,7 +21281,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -21307,7 +21307,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -21383,7 +21383,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -21409,7 +21409,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -21485,7 +21485,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -21511,7 +21511,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -21587,7 +21587,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -21613,7 +21613,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -21689,7 +21689,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -21715,7 +21715,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -21791,7 +21791,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -21817,7 +21817,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -21893,7 +21893,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -21919,7 +21919,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -21995,7 +21995,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -22021,7 +22021,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -22097,7 +22097,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -22123,7 +22123,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -22199,7 +22199,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -22225,7 +22225,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -22301,7 +22301,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -22327,7 +22327,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -22403,7 +22403,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -22429,7 +22429,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -22505,7 +22505,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -22531,7 +22531,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -22607,7 +22607,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -22633,7 +22633,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -22709,7 +22709,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -22735,7 +22735,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -22811,7 +22811,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -22837,7 +22837,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -22913,7 +22913,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -22939,7 +22939,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -23015,7 +23015,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -23041,7 +23041,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -23117,7 +23117,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -23143,7 +23143,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -23219,7 +23219,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -23245,7 +23245,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -23321,7 +23321,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -23347,7 +23347,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -23423,7 +23423,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -23449,7 +23449,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -23525,7 +23525,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -23551,7 +23551,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -23627,7 +23627,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -23653,7 +23653,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -23729,7 +23729,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -23755,7 +23755,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -23831,7 +23831,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -23857,7 +23857,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -23933,7 +23933,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -23959,7 +23959,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -24035,7 +24035,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -24061,7 +24061,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -24137,7 +24137,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -24163,7 +24163,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -24239,7 +24239,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -24265,7 +24265,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -24341,7 +24341,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -24367,7 +24367,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -24443,7 +24443,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -24469,7 +24469,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -24545,7 +24545,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -24571,7 +24571,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -24647,7 +24647,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -24673,7 +24673,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -24749,7 +24749,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -24775,7 +24775,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -24851,7 +24851,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -24877,7 +24877,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -24953,7 +24953,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -24979,7 +24979,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -25055,7 +25055,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -25081,7 +25081,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -25157,7 +25157,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -25183,7 +25183,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -25259,7 +25259,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -25285,7 +25285,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -25361,7 +25361,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -25387,7 +25387,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -25493,7 +25493,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -25519,7 +25519,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -25545,7 +25545,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -25571,7 +25571,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -25597,7 +25597,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -25623,7 +25623,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -25649,7 +25649,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -25675,7 +25675,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -25701,7 +25701,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -25727,7 +25727,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -25753,7 +25753,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25779,7 +25779,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -25805,7 +25805,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -25831,7 +25831,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -25857,7 +25857,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -25883,7 +25883,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -25909,7 +25909,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -25935,7 +25935,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -25961,7 +25961,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -25987,7 +25987,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -26013,7 +26013,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -26039,7 +26039,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -26065,7 +26065,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -26091,7 +26091,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -26117,7 +26117,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -26143,7 +26143,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -26169,7 +26169,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -26195,7 +26195,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -26221,7 +26221,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -26247,7 +26247,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -26273,7 +26273,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -26299,7 +26299,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -26325,7 +26325,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -26351,7 +26351,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -26377,7 +26377,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -26403,7 +26403,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -26429,7 +26429,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -26455,7 +26455,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -26481,7 +26481,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -26507,7 +26507,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -26533,7 +26533,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -26559,7 +26559,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -26585,7 +26585,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -26611,7 +26611,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -26637,7 +26637,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -26663,7 +26663,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -26689,7 +26689,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -26715,7 +26715,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -26741,7 +26741,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -26767,7 +26767,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -26793,7 +26793,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -26819,7 +26819,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -26845,7 +26845,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -26871,7 +26871,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -26897,7 +26897,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -26923,7 +26923,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -26949,7 +26949,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -26975,7 +26975,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -27001,7 +27001,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -27027,7 +27027,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -27053,7 +27053,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -27079,7 +27079,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -27105,7 +27105,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27131,7 +27131,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -27157,7 +27157,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -27183,7 +27183,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -27209,7 +27209,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -27235,7 +27235,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -27261,7 +27261,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -27287,7 +27287,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -27313,7 +27313,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -27339,7 +27339,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -27365,7 +27365,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -27391,7 +27391,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -27417,7 +27417,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -27443,7 +27443,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -27469,7 +27469,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -27495,7 +27495,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -27521,7 +27521,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -27547,7 +27547,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -27573,7 +27573,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -27599,7 +27599,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -27625,7 +27625,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -27651,7 +27651,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -27677,7 +27677,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -27703,7 +27703,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -27729,7 +27729,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -27755,7 +27755,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -27781,7 +27781,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -27807,7 +27807,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -27833,7 +27833,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -27859,7 +27859,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -27885,7 +27885,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -27911,7 +27911,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -27937,7 +27937,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -27963,7 +27963,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -27989,7 +27989,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -28015,7 +28015,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -28041,7 +28041,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -28067,7 +28067,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -28093,7 +28093,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -28119,7 +28119,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -28145,7 +28145,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28171,7 +28171,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -28197,7 +28197,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -28223,7 +28223,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -28249,7 +28249,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -28275,7 +28275,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -28301,7 +28301,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -28327,7 +28327,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -28353,7 +28353,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -28379,7 +28379,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -28405,7 +28405,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -28431,7 +28431,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -28457,7 +28457,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -28483,7 +28483,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -28509,7 +28509,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -28535,7 +28535,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -28561,7 +28561,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -28587,7 +28587,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -28613,7 +28613,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -28639,7 +28639,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -28665,7 +28665,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -28691,7 +28691,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -28717,7 +28717,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -28743,7 +28743,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -28769,7 +28769,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -28795,7 +28795,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -28821,7 +28821,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -28847,7 +28847,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -28873,7 +28873,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -28899,7 +28899,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -28925,7 +28925,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -28951,7 +28951,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -28977,7 +28977,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -29003,7 +29003,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -29029,7 +29029,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -29055,7 +29055,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -29081,7 +29081,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -29107,7 +29107,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -29133,7 +29133,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -29159,7 +29159,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -29185,7 +29185,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -29211,7 +29211,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -29237,7 +29237,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -29263,7 +29263,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -29289,7 +29289,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -29315,7 +29315,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -29341,7 +29341,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -29367,7 +29367,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -29393,7 +29393,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -29419,7 +29419,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -29445,7 +29445,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -29471,7 +29471,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -29497,7 +29497,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -29523,7 +29523,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -29549,7 +29549,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -29575,7 +29575,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -29601,7 +29601,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -29627,7 +29627,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -29653,7 +29653,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -29679,7 +29679,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -29705,7 +29705,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -29731,7 +29731,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -29757,7 +29757,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -29783,7 +29783,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -29809,7 +29809,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -29835,7 +29835,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -29861,7 +29861,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -29887,7 +29887,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -29913,7 +29913,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -29939,7 +29939,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -29965,7 +29965,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -29991,7 +29991,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -30017,7 +30017,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -30043,7 +30043,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -30069,7 +30069,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -30095,7 +30095,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -30121,7 +30121,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -30147,7 +30147,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -30173,7 +30173,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -30199,7 +30199,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -30225,7 +30225,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -30251,7 +30251,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -30277,7 +30277,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -30303,7 +30303,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -30329,7 +30329,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -30355,7 +30355,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -30381,7 +30381,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -30407,7 +30407,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -30513,7 +30513,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -30539,7 +30539,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -30615,7 +30615,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -30641,7 +30641,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -30717,7 +30717,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -30743,7 +30743,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -30819,7 +30819,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -30845,7 +30845,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -30921,7 +30921,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -30947,7 +30947,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -31023,7 +31023,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31049,7 +31049,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -31125,7 +31125,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -31151,7 +31151,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -31227,7 +31227,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -31253,7 +31253,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -31329,7 +31329,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -31355,7 +31355,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -31431,7 +31431,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -31457,7 +31457,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -31533,7 +31533,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -31559,7 +31559,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -31635,7 +31635,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -31661,7 +31661,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -31737,7 +31737,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -31763,7 +31763,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -31839,7 +31839,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -31865,7 +31865,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -31941,7 +31941,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -31967,7 +31967,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -32043,7 +32043,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -32069,7 +32069,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -32145,7 +32145,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -32171,7 +32171,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -32247,7 +32247,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -32273,7 +32273,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -32349,7 +32349,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -32375,7 +32375,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -32451,7 +32451,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -32477,7 +32477,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -32553,7 +32553,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -32579,7 +32579,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -32655,7 +32655,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -32681,7 +32681,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -32757,7 +32757,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -32783,7 +32783,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -32859,7 +32859,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -32885,7 +32885,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -32961,7 +32961,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -32987,7 +32987,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -33063,7 +33063,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -33089,7 +33089,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -33165,7 +33165,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -33191,7 +33191,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -33267,7 +33267,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -33293,7 +33293,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -33369,7 +33369,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -33395,7 +33395,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -33471,7 +33471,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -33497,7 +33497,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -33573,7 +33573,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -33599,7 +33599,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -33675,7 +33675,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33701,7 +33701,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -33777,7 +33777,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -33803,7 +33803,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -33879,7 +33879,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -33905,7 +33905,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -33981,7 +33981,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -34007,7 +34007,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -34083,7 +34083,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -34109,7 +34109,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -34185,7 +34185,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -34211,7 +34211,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -34287,7 +34287,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -34313,7 +34313,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -34389,7 +34389,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -34415,7 +34415,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -34491,7 +34491,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -34517,7 +34517,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -34593,7 +34593,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -34619,7 +34619,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -34695,7 +34695,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -34721,7 +34721,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -34797,7 +34797,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -34823,7 +34823,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -34899,7 +34899,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -34925,7 +34925,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -35001,7 +35001,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -35027,7 +35027,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -35103,7 +35103,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -35129,7 +35129,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -35205,7 +35205,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -35231,7 +35231,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -35307,7 +35307,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -35333,7 +35333,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -35409,7 +35409,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -35435,7 +35435,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -35511,7 +35511,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -35537,7 +35537,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -35613,7 +35613,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -35639,7 +35639,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -35715,7 +35715,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35741,7 +35741,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -35817,7 +35817,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -35843,7 +35843,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -35919,7 +35919,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -35945,7 +35945,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -36021,7 +36021,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -36047,7 +36047,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -36123,7 +36123,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -36149,7 +36149,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -36225,7 +36225,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -36251,7 +36251,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -36327,7 +36327,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -36353,7 +36353,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -36429,7 +36429,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -36455,7 +36455,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -36531,7 +36531,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -36557,7 +36557,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -36633,7 +36633,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -36659,7 +36659,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -36735,7 +36735,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -36761,7 +36761,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -36837,7 +36837,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -36863,7 +36863,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -36939,7 +36939,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -36965,7 +36965,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -37041,7 +37041,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -37067,7 +37067,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -37143,7 +37143,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -37169,7 +37169,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -37245,7 +37245,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -37271,7 +37271,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -37347,7 +37347,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -37373,7 +37373,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -37449,7 +37449,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -37475,7 +37475,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -37551,7 +37551,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -37577,7 +37577,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -37653,7 +37653,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -37679,7 +37679,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -37755,7 +37755,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -37781,7 +37781,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -37857,7 +37857,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -37883,7 +37883,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -37959,7 +37959,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -37985,7 +37985,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -38061,7 +38061,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -38087,7 +38087,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -38163,7 +38163,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -38189,7 +38189,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -38265,7 +38265,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -38291,7 +38291,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -38367,7 +38367,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -38393,7 +38393,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -38469,7 +38469,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38495,7 +38495,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -38571,7 +38571,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -38597,7 +38597,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -38673,7 +38673,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -38699,7 +38699,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -38775,7 +38775,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -38801,7 +38801,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -38877,7 +38877,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -38903,7 +38903,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -38979,7 +38979,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -39005,7 +39005,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -39081,7 +39081,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -39107,7 +39107,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -39183,7 +39183,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -39209,7 +39209,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -39285,7 +39285,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -39311,7 +39311,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -39387,7 +39387,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -39413,7 +39413,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -39489,7 +39489,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -39515,7 +39515,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -39591,7 +39591,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -39617,7 +39617,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -39693,7 +39693,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -39719,7 +39719,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -39795,7 +39795,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -39821,7 +39821,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -39897,7 +39897,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -39923,7 +39923,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -39999,7 +39999,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40025,7 +40025,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40101,7 +40101,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -40127,7 +40127,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -40233,7 +40233,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -40259,7 +40259,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -40285,7 +40285,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -40311,7 +40311,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -40337,7 +40337,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -40363,7 +40363,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -40389,7 +40389,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -40415,7 +40415,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -40441,7 +40441,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -40467,7 +40467,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -40493,7 +40493,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -40519,7 +40519,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -40545,7 +40545,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -40571,7 +40571,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -40597,7 +40597,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -40623,7 +40623,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -40649,7 +40649,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40675,7 +40675,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -40701,7 +40701,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -40727,7 +40727,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -40753,7 +40753,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -40779,7 +40779,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -40805,7 +40805,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -40831,7 +40831,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -40857,7 +40857,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -40883,7 +40883,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -40909,7 +40909,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -40935,7 +40935,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -40961,7 +40961,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -40987,7 +40987,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -41013,7 +41013,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -41039,7 +41039,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -41065,7 +41065,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -41091,7 +41091,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -41117,7 +41117,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -41143,7 +41143,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -41169,7 +41169,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -41195,7 +41195,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -41221,7 +41221,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -41247,7 +41247,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -41273,7 +41273,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -41299,7 +41299,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -41325,7 +41325,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -41351,7 +41351,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -41377,7 +41377,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -41403,7 +41403,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -41429,7 +41429,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -41455,7 +41455,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -41481,7 +41481,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -41507,7 +41507,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -41533,7 +41533,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41559,7 +41559,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -41585,7 +41585,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -41611,7 +41611,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -41637,7 +41637,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -41663,7 +41663,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -41689,7 +41689,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -41715,7 +41715,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -41741,7 +41741,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -41767,7 +41767,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -41793,7 +41793,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -41819,7 +41819,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -41845,7 +41845,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -41871,7 +41871,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -41897,7 +41897,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -41923,7 +41923,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -41949,7 +41949,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -41975,7 +41975,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -42001,7 +42001,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -42027,7 +42027,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -42053,7 +42053,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -42079,7 +42079,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -42105,7 +42105,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -42131,7 +42131,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -42157,7 +42157,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -42183,7 +42183,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -42209,7 +42209,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -42235,7 +42235,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -42261,7 +42261,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -42287,7 +42287,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -42313,7 +42313,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -42339,7 +42339,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -42365,7 +42365,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -42391,7 +42391,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -42417,7 +42417,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -42443,7 +42443,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -42469,7 +42469,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -42495,7 +42495,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -42521,7 +42521,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -42547,7 +42547,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -42573,7 +42573,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -42599,7 +42599,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -42625,7 +42625,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -42651,7 +42651,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -42677,7 +42677,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -42703,7 +42703,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -42729,7 +42729,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -42755,7 +42755,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -42781,7 +42781,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -42807,7 +42807,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -42833,7 +42833,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -42859,7 +42859,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -42885,7 +42885,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -42911,7 +42911,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -42937,7 +42937,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -42963,7 +42963,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -42989,7 +42989,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -43015,7 +43015,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -43041,7 +43041,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -43067,7 +43067,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -43093,7 +43093,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -43119,7 +43119,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -43145,7 +43145,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -43171,7 +43171,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -43197,7 +43197,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -43223,7 +43223,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -43249,7 +43249,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -43275,7 +43275,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -43301,7 +43301,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -43327,7 +43327,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -43353,7 +43353,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -43379,7 +43379,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -43405,7 +43405,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43431,7 +43431,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -43457,7 +43457,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -43483,7 +43483,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -43509,7 +43509,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -43535,7 +43535,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -43561,7 +43561,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -43587,7 +43587,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -43613,7 +43613,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -43639,7 +43639,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -43665,7 +43665,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -43691,7 +43691,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -43717,7 +43717,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -43743,7 +43743,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -43769,7 +43769,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -43795,7 +43795,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -43821,7 +43821,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -43847,7 +43847,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -43873,7 +43873,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -43899,7 +43899,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -43925,7 +43925,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -43951,7 +43951,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -43977,7 +43977,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -44003,7 +44003,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -44029,7 +44029,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -44055,7 +44055,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -44081,7 +44081,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -44107,7 +44107,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -44133,7 +44133,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -44159,7 +44159,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -44185,7 +44185,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -44211,7 +44211,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -44237,7 +44237,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -44263,7 +44263,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -44289,7 +44289,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44315,7 +44315,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -44341,7 +44341,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -44367,7 +44367,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -44393,7 +44393,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -44419,7 +44419,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -44445,7 +44445,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -44471,7 +44471,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -44497,7 +44497,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -44523,7 +44523,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -44549,7 +44549,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -44575,7 +44575,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -44601,7 +44601,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -44627,7 +44627,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -44653,7 +44653,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -44679,7 +44679,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -44705,7 +44705,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -44731,7 +44731,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -44757,7 +44757,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -44783,7 +44783,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -44809,7 +44809,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -44835,7 +44835,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -44861,7 +44861,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -44887,7 +44887,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -44913,7 +44913,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -44939,7 +44939,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -44965,7 +44965,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -44991,7 +44991,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -45017,7 +45017,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -45043,7 +45043,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -45069,7 +45069,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45095,7 +45095,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -45121,7 +45121,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -45147,7 +45147,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -45253,7 +45253,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -45279,7 +45279,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -45355,7 +45355,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -45381,7 +45381,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -45457,7 +45457,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -45483,7 +45483,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -45559,7 +45559,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -45585,7 +45585,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -45661,7 +45661,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -45687,7 +45687,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -45763,7 +45763,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -45789,7 +45789,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -45865,7 +45865,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -45891,7 +45891,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -45967,7 +45967,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -45993,7 +45993,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -46069,7 +46069,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46095,7 +46095,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -46171,7 +46171,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -46197,7 +46197,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -46273,7 +46273,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -46299,7 +46299,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -46375,7 +46375,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -46401,7 +46401,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -46477,7 +46477,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -46503,7 +46503,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -46579,7 +46579,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -46605,7 +46605,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -46681,7 +46681,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -46707,7 +46707,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -46783,7 +46783,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -46809,7 +46809,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -46885,7 +46885,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -46911,7 +46911,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -46987,7 +46987,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -47013,7 +47013,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -47089,7 +47089,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -47115,7 +47115,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -47191,7 +47191,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -47217,7 +47217,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -47293,7 +47293,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -47319,7 +47319,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -47395,7 +47395,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -47421,7 +47421,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -47497,7 +47497,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -47523,7 +47523,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -47599,7 +47599,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -47625,7 +47625,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -47701,7 +47701,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -47727,7 +47727,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -47803,7 +47803,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47829,7 +47829,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -47905,7 +47905,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -47931,7 +47931,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -48007,7 +48007,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -48033,7 +48033,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -48109,7 +48109,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -48135,7 +48135,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -48211,7 +48211,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -48237,7 +48237,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -48313,7 +48313,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -48339,7 +48339,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -48415,7 +48415,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -48441,7 +48441,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -48517,7 +48517,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -48543,7 +48543,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -48619,7 +48619,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -48645,7 +48645,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -48721,7 +48721,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -48747,7 +48747,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -48823,7 +48823,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -48849,7 +48849,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -48925,7 +48925,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -48951,7 +48951,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -49027,7 +49027,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -49053,7 +49053,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -49129,7 +49129,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -49155,7 +49155,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -49231,7 +49231,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -49257,7 +49257,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -49333,7 +49333,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -49359,7 +49359,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -49435,7 +49435,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -49461,7 +49461,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -49537,7 +49537,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -49563,7 +49563,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -49639,7 +49639,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -49665,7 +49665,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -49741,7 +49741,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -49767,7 +49767,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -49843,7 +49843,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -49869,7 +49869,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -49945,7 +49945,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -49971,7 +49971,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -50047,7 +50047,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -50073,7 +50073,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -50149,7 +50149,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -50175,7 +50175,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -50251,7 +50251,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -50277,7 +50277,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -50353,7 +50353,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -50379,7 +50379,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -50455,7 +50455,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -50481,7 +50481,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -50557,7 +50557,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -50583,7 +50583,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -50659,7 +50659,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -50685,7 +50685,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -50761,7 +50761,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -50787,7 +50787,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -50863,7 +50863,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -50889,7 +50889,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -50965,7 +50965,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -50991,7 +50991,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -51067,7 +51067,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -51093,7 +51093,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -51169,7 +51169,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -51195,7 +51195,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -51271,7 +51271,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -51297,7 +51297,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -51373,7 +51373,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -51399,7 +51399,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -51475,7 +51475,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51501,7 +51501,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -51577,7 +51577,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -51603,7 +51603,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -51679,7 +51679,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -51705,7 +51705,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -51781,7 +51781,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -51807,7 +51807,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -51883,7 +51883,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -51909,7 +51909,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -51985,7 +51985,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -52011,7 +52011,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -52087,7 +52087,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -52113,7 +52113,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -52189,7 +52189,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -52215,7 +52215,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -52291,7 +52291,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -52317,7 +52317,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -52393,7 +52393,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -52419,7 +52419,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -52495,7 +52495,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -52521,7 +52521,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -52597,7 +52597,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -52623,7 +52623,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -52699,7 +52699,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -52725,7 +52725,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -52801,7 +52801,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -52827,7 +52827,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -52903,7 +52903,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -52929,7 +52929,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -53005,7 +53005,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -53031,7 +53031,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -53107,7 +53107,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -53133,7 +53133,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -53209,7 +53209,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53235,7 +53235,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -53311,7 +53311,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -53337,7 +53337,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -53413,7 +53413,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -53439,7 +53439,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -53515,7 +53515,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -53541,7 +53541,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -53617,7 +53617,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -53643,7 +53643,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -53719,7 +53719,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -53745,7 +53745,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -53821,7 +53821,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -53847,7 +53847,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -53923,7 +53923,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -53949,7 +53949,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -54025,7 +54025,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -54051,7 +54051,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -54127,7 +54127,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -54153,7 +54153,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -54229,7 +54229,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -54255,7 +54255,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -54331,7 +54331,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -54357,7 +54357,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -54433,7 +54433,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -54459,7 +54459,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -54535,7 +54535,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -54561,7 +54561,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -54637,7 +54637,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -54663,7 +54663,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -54739,7 +54739,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -54765,7 +54765,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -54841,7 +54841,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -54867,7 +54867,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -54973,7 +54973,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -54999,7 +54999,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -55025,7 +55025,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -55051,7 +55051,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -55077,7 +55077,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -55103,7 +55103,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -55129,7 +55129,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -55155,7 +55155,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -55181,7 +55181,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -55207,7 +55207,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -55233,7 +55233,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -55259,7 +55259,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -55285,7 +55285,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -55311,7 +55311,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -55337,7 +55337,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -55363,7 +55363,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -55389,7 +55389,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -55415,7 +55415,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -55441,7 +55441,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -55467,7 +55467,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -55493,7 +55493,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -55519,7 +55519,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -55545,7 +55545,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -55571,7 +55571,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -55597,7 +55597,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -55623,7 +55623,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -55649,7 +55649,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -55675,7 +55675,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -55701,7 +55701,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -55727,7 +55727,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -55753,7 +55753,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -55779,7 +55779,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -55805,7 +55805,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -55831,7 +55831,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -55857,7 +55857,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -55883,7 +55883,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -55909,7 +55909,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -55935,7 +55935,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -55961,7 +55961,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -55987,7 +55987,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -56013,7 +56013,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -56039,7 +56039,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -56065,7 +56065,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -56091,7 +56091,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -56117,7 +56117,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -56143,7 +56143,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -56169,7 +56169,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -56195,7 +56195,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -56221,7 +56221,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -56247,7 +56247,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -56273,7 +56273,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56299,7 +56299,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -56325,7 +56325,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -56351,7 +56351,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -56377,7 +56377,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -56403,7 +56403,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -56429,7 +56429,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -56455,7 +56455,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -56481,7 +56481,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -56507,7 +56507,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -56533,7 +56533,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -56559,7 +56559,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -56585,7 +56585,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -56611,7 +56611,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -56637,7 +56637,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -56663,7 +56663,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -56689,7 +56689,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -56715,7 +56715,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -56741,7 +56741,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -56767,7 +56767,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -56793,7 +56793,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -56819,7 +56819,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -56845,7 +56845,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -56871,7 +56871,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -56897,7 +56897,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -56923,7 +56923,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -56949,7 +56949,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -56975,7 +56975,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -57001,7 +57001,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -57027,7 +57027,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -57053,7 +57053,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -57079,7 +57079,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -57105,7 +57105,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -57131,7 +57131,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -57157,7 +57157,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -57183,7 +57183,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -57209,7 +57209,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -57235,7 +57235,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -57261,7 +57261,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -57287,7 +57287,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -57313,7 +57313,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -57339,7 +57339,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -57365,7 +57365,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -57391,7 +57391,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -57417,7 +57417,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -57443,7 +57443,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -57469,7 +57469,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -57495,7 +57495,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -57521,7 +57521,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -57547,7 +57547,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -57573,7 +57573,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -57599,7 +57599,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -57625,7 +57625,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -57651,7 +57651,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -57677,7 +57677,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -57703,7 +57703,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -57729,7 +57729,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -57755,7 +57755,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -57781,7 +57781,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -57807,7 +57807,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -57833,7 +57833,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -57859,7 +57859,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -57885,7 +57885,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -57911,7 +57911,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -57937,7 +57937,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -57963,7 +57963,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -57989,7 +57989,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -58015,7 +58015,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -58041,7 +58041,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -58067,7 +58067,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -58093,7 +58093,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -58119,7 +58119,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -58145,7 +58145,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58171,7 +58171,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -58197,7 +58197,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -58223,7 +58223,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -58249,7 +58249,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -58275,7 +58275,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -58301,7 +58301,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -58327,7 +58327,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -58353,7 +58353,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -58379,7 +58379,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -58405,7 +58405,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -58431,7 +58431,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -58457,7 +58457,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -58483,7 +58483,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -58509,7 +58509,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -58535,7 +58535,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -58561,7 +58561,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -58587,7 +58587,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -58613,7 +58613,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -58639,7 +58639,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -58665,7 +58665,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -58691,7 +58691,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -58717,7 +58717,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -58743,7 +58743,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -58769,7 +58769,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -58795,7 +58795,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -58821,7 +58821,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -58847,7 +58847,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -58873,7 +58873,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -58899,7 +58899,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -58925,7 +58925,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -58951,7 +58951,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -58977,7 +58977,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -59003,7 +59003,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -59029,7 +59029,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59055,7 +59055,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59081,7 +59081,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -59107,7 +59107,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -59133,7 +59133,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -59159,7 +59159,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -59185,7 +59185,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -59211,7 +59211,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -59237,7 +59237,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -59263,7 +59263,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -59289,7 +59289,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -59315,7 +59315,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -59341,7 +59341,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -59367,7 +59367,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -59393,7 +59393,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -59419,7 +59419,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -59445,7 +59445,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -59471,7 +59471,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -59497,7 +59497,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -59523,7 +59523,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -59549,7 +59549,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -59575,7 +59575,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -59601,7 +59601,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -59627,7 +59627,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -59653,7 +59653,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -59679,7 +59679,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -59705,7 +59705,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -59731,7 +59731,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -59757,7 +59757,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -59783,7 +59783,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -59809,7 +59809,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59835,7 +59835,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -59861,7 +59861,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -59887,7 +59887,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -59993,7 +59993,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -60019,7 +60019,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -60095,7 +60095,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -60121,7 +60121,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -60197,7 +60197,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -60223,7 +60223,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -60299,7 +60299,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -60325,7 +60325,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -60401,7 +60401,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -60427,7 +60427,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -60503,7 +60503,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -60529,7 +60529,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -60605,7 +60605,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -60631,7 +60631,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -60707,7 +60707,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -60733,7 +60733,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -60809,7 +60809,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60835,7 +60835,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -60911,7 +60911,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -60937,7 +60937,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -61013,7 +61013,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -61039,7 +61039,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -61115,7 +61115,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -61141,7 +61141,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -61217,7 +61217,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -61243,7 +61243,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -61319,7 +61319,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -61345,7 +61345,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -61421,7 +61421,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -61447,7 +61447,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -61523,7 +61523,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -61549,7 +61549,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -61625,7 +61625,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -61651,7 +61651,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -61727,7 +61727,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -61753,7 +61753,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -61829,7 +61829,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -61855,7 +61855,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -61931,7 +61931,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -61957,7 +61957,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -62033,7 +62033,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -62059,7 +62059,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -62135,7 +62135,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -62161,7 +62161,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -62237,7 +62237,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -62263,7 +62263,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -62339,7 +62339,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -62365,7 +62365,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -62441,7 +62441,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -62467,7 +62467,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -62543,7 +62543,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -62569,7 +62569,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -62645,7 +62645,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -62671,7 +62671,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -62747,7 +62747,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -62773,7 +62773,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -62849,7 +62849,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -62875,7 +62875,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -62951,7 +62951,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -62977,7 +62977,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -63053,7 +63053,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -63079,7 +63079,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -63155,7 +63155,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -63181,7 +63181,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -63257,7 +63257,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -63283,7 +63283,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -63359,7 +63359,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -63385,7 +63385,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -63461,7 +63461,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -63487,7 +63487,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -63563,7 +63563,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -63589,7 +63589,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -63665,7 +63665,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -63691,7 +63691,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -63767,7 +63767,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -63793,7 +63793,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -63869,7 +63869,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -63895,7 +63895,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -63971,7 +63971,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -63997,7 +63997,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -64073,7 +64073,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -64099,7 +64099,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -64175,7 +64175,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -64201,7 +64201,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -64277,7 +64277,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -64303,7 +64303,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -64379,7 +64379,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -64405,7 +64405,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -64481,7 +64481,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -64507,7 +64507,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -64583,7 +64583,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -64609,7 +64609,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -64685,7 +64685,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -64711,7 +64711,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -64787,7 +64787,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -64813,7 +64813,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -64889,7 +64889,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -64915,7 +64915,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -64991,7 +64991,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -65017,7 +65017,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -65093,7 +65093,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -65119,7 +65119,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -65195,7 +65195,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -65221,7 +65221,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -65297,7 +65297,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -65323,7 +65323,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -65399,7 +65399,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -65425,7 +65425,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -65501,7 +65501,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -65527,7 +65527,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -65603,7 +65603,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -65629,7 +65629,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -65705,7 +65705,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -65731,7 +65731,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -65807,7 +65807,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -65833,7 +65833,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -65909,7 +65909,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -65935,7 +65935,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -66011,7 +66011,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -66037,7 +66037,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -66113,7 +66113,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -66139,7 +66139,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -66215,7 +66215,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -66241,7 +66241,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -66317,7 +66317,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -66343,7 +66343,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -66419,7 +66419,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -66445,7 +66445,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -66521,7 +66521,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -66547,7 +66547,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -66623,7 +66623,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -66649,7 +66649,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -66725,7 +66725,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -66751,7 +66751,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -66827,7 +66827,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -66853,7 +66853,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -66929,7 +66929,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -66955,7 +66955,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -67031,7 +67031,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -67057,7 +67057,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -67133,7 +67133,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -67159,7 +67159,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -67235,7 +67235,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -67261,7 +67261,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -67337,7 +67337,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -67363,7 +67363,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -67439,7 +67439,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -67465,7 +67465,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -67541,7 +67541,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -67567,7 +67567,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -67643,7 +67643,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -67669,7 +67669,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -67745,7 +67745,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -67771,7 +67771,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -67847,7 +67847,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -67873,7 +67873,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -67949,7 +67949,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -67975,7 +67975,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -68051,7 +68051,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -68077,7 +68077,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -68153,7 +68153,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -68179,7 +68179,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -68255,7 +68255,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -68281,7 +68281,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -68357,7 +68357,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -68383,7 +68383,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -68459,7 +68459,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -68485,7 +68485,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -68561,7 +68561,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -68587,7 +68587,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -68663,7 +68663,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -68689,7 +68689,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -68765,7 +68765,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -68791,7 +68791,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -68867,7 +68867,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -68893,7 +68893,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -68969,7 +68969,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -68995,7 +68995,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -69071,7 +69071,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -69097,7 +69097,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -69173,7 +69173,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -69199,7 +69199,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -69275,7 +69275,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -69301,7 +69301,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -69377,7 +69377,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -69403,7 +69403,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -69479,7 +69479,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69505,7 +69505,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -69581,7 +69581,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -69607,7 +69607,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -69713,7 +69713,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -69739,7 +69739,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -69765,7 +69765,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -69791,7 +69791,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -69817,7 +69817,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -69843,7 +69843,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -69869,7 +69869,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -69895,7 +69895,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -69921,7 +69921,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -69947,7 +69947,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -69973,7 +69973,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -69999,7 +69999,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -70025,7 +70025,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -70051,7 +70051,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -70077,7 +70077,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -70103,7 +70103,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -70129,7 +70129,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -70155,7 +70155,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -70181,7 +70181,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -70207,7 +70207,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -70233,7 +70233,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -70259,7 +70259,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -70285,7 +70285,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -70311,7 +70311,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -70337,7 +70337,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -70363,7 +70363,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -70389,7 +70389,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -70415,7 +70415,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -70441,7 +70441,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -70467,7 +70467,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -70493,7 +70493,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -70519,7 +70519,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -70545,7 +70545,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -70571,7 +70571,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -70597,7 +70597,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -70623,7 +70623,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -70649,7 +70649,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -70675,7 +70675,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -70701,7 +70701,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -70727,7 +70727,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -70753,7 +70753,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -70779,7 +70779,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -70805,7 +70805,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -70831,7 +70831,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -70857,7 +70857,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -70883,7 +70883,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -70909,7 +70909,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -70935,7 +70935,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -70961,7 +70961,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -70987,7 +70987,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -71013,7 +71013,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71039,7 +71039,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -71065,7 +71065,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -71091,7 +71091,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -71117,7 +71117,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -71143,7 +71143,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -71169,7 +71169,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -71195,7 +71195,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -71221,7 +71221,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -71247,7 +71247,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -71273,7 +71273,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -71299,7 +71299,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -71325,7 +71325,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -71351,7 +71351,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -71377,7 +71377,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -71403,7 +71403,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -71429,7 +71429,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -71455,7 +71455,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -71481,7 +71481,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -71507,7 +71507,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -71533,7 +71533,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -71559,7 +71559,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -71585,7 +71585,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -71611,7 +71611,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -71637,7 +71637,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -71663,7 +71663,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -71689,7 +71689,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -71715,7 +71715,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -71741,7 +71741,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -71767,7 +71767,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -71793,7 +71793,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -71819,7 +71819,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -71845,7 +71845,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -71871,7 +71871,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -71897,7 +71897,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -71923,7 +71923,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -71949,7 +71949,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -71975,7 +71975,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -72001,7 +72001,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -72027,7 +72027,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -72053,7 +72053,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -72079,7 +72079,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -72105,7 +72105,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -72131,7 +72131,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -72157,7 +72157,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -72183,7 +72183,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -72209,7 +72209,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -72235,7 +72235,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -72261,7 +72261,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -72287,7 +72287,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -72313,7 +72313,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -72339,7 +72339,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -72365,7 +72365,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -72391,7 +72391,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -72417,7 +72417,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -72443,7 +72443,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -72469,7 +72469,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -72495,7 +72495,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -72521,7 +72521,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -72547,7 +72547,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -72573,7 +72573,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -72599,7 +72599,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -72625,7 +72625,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -72651,7 +72651,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -72677,7 +72677,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -72703,7 +72703,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -72729,7 +72729,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -72755,7 +72755,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -72781,7 +72781,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -72807,7 +72807,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -72833,7 +72833,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -72859,7 +72859,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -72885,7 +72885,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -72911,7 +72911,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -72937,7 +72937,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -72963,7 +72963,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -72989,7 +72989,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -73015,7 +73015,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -73041,7 +73041,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -73067,7 +73067,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -73093,7 +73093,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -73119,7 +73119,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -73145,7 +73145,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -73171,7 +73171,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -73197,7 +73197,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -73223,7 +73223,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -73249,7 +73249,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -73275,7 +73275,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -73301,7 +73301,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -73327,7 +73327,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -73353,7 +73353,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -73379,7 +73379,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -73405,7 +73405,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -73431,7 +73431,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -73457,7 +73457,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -73483,7 +73483,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -73509,7 +73509,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -73535,7 +73535,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -73561,7 +73561,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -73587,7 +73587,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -73613,7 +73613,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -73639,7 +73639,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -73665,7 +73665,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -73691,7 +73691,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -73717,7 +73717,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -73743,7 +73743,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -73769,7 +73769,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -73795,7 +73795,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -73821,7 +73821,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -73847,7 +73847,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -73873,7 +73873,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -73899,7 +73899,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -73925,7 +73925,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -73951,7 +73951,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -73977,7 +73977,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -74003,7 +74003,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -74029,7 +74029,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -74055,7 +74055,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -74081,7 +74081,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -74107,7 +74107,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -74133,7 +74133,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -74159,7 +74159,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -74185,7 +74185,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -74211,7 +74211,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -74237,7 +74237,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -74263,7 +74263,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -74289,7 +74289,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -74315,7 +74315,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -74341,7 +74341,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -74367,7 +74367,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -74393,7 +74393,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -74419,7 +74419,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -74445,7 +74445,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -74471,7 +74471,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -74497,7 +74497,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -74523,7 +74523,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -74549,7 +74549,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -74575,7 +74575,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -74601,7 +74601,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -74627,7 +74627,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -74733,7 +74733,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -74759,7 +74759,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -74835,7 +74835,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -74861,7 +74861,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -74937,7 +74937,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -74963,7 +74963,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -75039,7 +75039,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -75065,7 +75065,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -75141,7 +75141,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -75167,7 +75167,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -75243,7 +75243,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -75269,7 +75269,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -75345,7 +75345,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -75371,7 +75371,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -75447,7 +75447,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -75473,7 +75473,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -75549,7 +75549,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75575,7 +75575,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -75651,7 +75651,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -75677,7 +75677,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -75753,7 +75753,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -75779,7 +75779,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -75855,7 +75855,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -75881,7 +75881,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -75957,7 +75957,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -75983,7 +75983,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -76059,7 +76059,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -76085,7 +76085,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -76161,7 +76161,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -76187,7 +76187,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -76263,7 +76263,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -76289,7 +76289,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -76365,7 +76365,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -76391,7 +76391,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -76467,7 +76467,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -76493,7 +76493,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -76569,7 +76569,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -76595,7 +76595,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -76671,7 +76671,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -76697,7 +76697,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -76773,7 +76773,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -76799,7 +76799,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -76875,7 +76875,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -76901,7 +76901,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -76977,7 +76977,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -77003,7 +77003,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -77079,7 +77079,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -77105,7 +77105,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -77181,7 +77181,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -77207,7 +77207,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -77283,7 +77283,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77309,7 +77309,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -77385,7 +77385,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -77411,7 +77411,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -77487,7 +77487,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -77513,7 +77513,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -77589,7 +77589,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -77615,7 +77615,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -77691,7 +77691,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -77717,7 +77717,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -77793,7 +77793,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -77819,7 +77819,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -77895,7 +77895,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -77921,7 +77921,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -77997,7 +77997,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -78023,7 +78023,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -78099,7 +78099,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -78125,7 +78125,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -78201,7 +78201,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -78227,7 +78227,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -78303,7 +78303,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -78329,7 +78329,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -78405,7 +78405,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -78431,7 +78431,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -78507,7 +78507,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -78533,7 +78533,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -78609,7 +78609,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -78635,7 +78635,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -78711,7 +78711,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -78737,7 +78737,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -78813,7 +78813,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -78839,7 +78839,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -78915,7 +78915,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -78941,7 +78941,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -79017,7 +79017,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -79043,7 +79043,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -79119,7 +79119,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -79145,7 +79145,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -79221,7 +79221,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -79247,7 +79247,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -79323,7 +79323,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -79349,7 +79349,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -79425,7 +79425,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -79451,7 +79451,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -79527,7 +79527,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -79553,7 +79553,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -79629,7 +79629,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -79655,7 +79655,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -79731,7 +79731,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -79757,7 +79757,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -79833,7 +79833,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -79859,7 +79859,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -79935,7 +79935,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -79961,7 +79961,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -80037,7 +80037,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -80063,7 +80063,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -80139,7 +80139,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -80165,7 +80165,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -80241,7 +80241,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -80267,7 +80267,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -80343,7 +80343,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -80369,7 +80369,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -80445,7 +80445,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -80471,7 +80471,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -80547,7 +80547,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -80573,7 +80573,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -80649,7 +80649,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -80675,7 +80675,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -80751,7 +80751,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -80777,7 +80777,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -80853,7 +80853,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -80879,7 +80879,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -80955,7 +80955,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -80981,7 +80981,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -81057,7 +81057,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -81083,7 +81083,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -81159,7 +81159,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -81185,7 +81185,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -81261,7 +81261,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -81287,7 +81287,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -81363,7 +81363,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -81389,7 +81389,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -81465,7 +81465,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -81491,7 +81491,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -81567,7 +81567,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -81593,7 +81593,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -81669,7 +81669,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -81695,7 +81695,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -81771,7 +81771,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -81797,7 +81797,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -81873,7 +81873,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -81899,7 +81899,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -81975,7 +81975,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -82001,7 +82001,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -82077,7 +82077,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -82103,7 +82103,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -82179,7 +82179,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -82205,7 +82205,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -82281,7 +82281,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -82307,7 +82307,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -82383,7 +82383,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -82409,7 +82409,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -82485,7 +82485,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -82511,7 +82511,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -82587,7 +82587,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -82613,7 +82613,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -82689,7 +82689,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -82715,7 +82715,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -82791,7 +82791,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -82817,7 +82817,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -82893,7 +82893,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -82919,7 +82919,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -82995,7 +82995,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -83021,7 +83021,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -83097,7 +83097,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -83123,7 +83123,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -83199,7 +83199,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -83225,7 +83225,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -83301,7 +83301,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -83327,7 +83327,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -83403,7 +83403,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -83429,7 +83429,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -83505,7 +83505,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -83531,7 +83531,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -83607,7 +83607,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -83633,7 +83633,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -83709,7 +83709,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -83735,7 +83735,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -83811,7 +83811,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -83837,7 +83837,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -83913,7 +83913,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -83939,7 +83939,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -84015,7 +84015,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -84041,7 +84041,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -84117,7 +84117,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -84143,7 +84143,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -84219,7 +84219,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84245,7 +84245,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84321,7 +84321,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -84347,7 +84347,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -84453,7 +84453,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -84479,7 +84479,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -84505,7 +84505,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -84531,7 +84531,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -84557,7 +84557,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -84583,7 +84583,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -84609,7 +84609,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -84635,7 +84635,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -84661,7 +84661,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -84687,7 +84687,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -84713,7 +84713,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -84739,7 +84739,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -84765,7 +84765,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -84791,7 +84791,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -84817,7 +84817,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -84843,7 +84843,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -84869,7 +84869,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84895,7 +84895,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -84921,7 +84921,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -84947,7 +84947,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -84973,7 +84973,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -84999,7 +84999,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -85025,7 +85025,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -85051,7 +85051,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -85077,7 +85077,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -85103,7 +85103,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -85129,7 +85129,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -85155,7 +85155,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -85181,7 +85181,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -85207,7 +85207,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -85233,7 +85233,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -85259,7 +85259,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -85285,7 +85285,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -85311,7 +85311,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -85337,7 +85337,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -85363,7 +85363,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -85389,7 +85389,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -85415,7 +85415,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -85441,7 +85441,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -85467,7 +85467,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -85493,7 +85493,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -85519,7 +85519,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -85545,7 +85545,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -85571,7 +85571,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -85597,7 +85597,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -85623,7 +85623,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -85649,7 +85649,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -85675,7 +85675,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -85701,7 +85701,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -85727,7 +85727,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -85753,7 +85753,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85779,7 +85779,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -85805,7 +85805,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -85831,7 +85831,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -85857,7 +85857,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -85883,7 +85883,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -85909,7 +85909,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -85935,7 +85935,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -85961,7 +85961,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -85987,7 +85987,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -86013,7 +86013,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -86039,7 +86039,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -86065,7 +86065,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -86091,7 +86091,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -86117,7 +86117,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -86143,7 +86143,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -86169,7 +86169,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -86195,7 +86195,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -86221,7 +86221,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -86247,7 +86247,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -86273,7 +86273,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -86299,7 +86299,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -86325,7 +86325,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -86351,7 +86351,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -86377,7 +86377,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -86403,7 +86403,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -86429,7 +86429,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -86455,7 +86455,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -86481,7 +86481,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -86507,7 +86507,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -86533,7 +86533,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -86559,7 +86559,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -86585,7 +86585,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -86611,7 +86611,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -86637,7 +86637,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -86663,7 +86663,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -86689,7 +86689,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -86715,7 +86715,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -86741,7 +86741,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -86767,7 +86767,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -86793,7 +86793,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -86819,7 +86819,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -86845,7 +86845,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -86871,7 +86871,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -86897,7 +86897,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -86923,7 +86923,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -86949,7 +86949,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -86975,7 +86975,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -87001,7 +87001,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -87027,7 +87027,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -87053,7 +87053,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -87079,7 +87079,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -87105,7 +87105,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -87131,7 +87131,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -87157,7 +87157,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -87183,7 +87183,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -87209,7 +87209,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -87235,7 +87235,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -87261,7 +87261,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -87287,7 +87287,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -87313,7 +87313,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -87339,7 +87339,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -87365,7 +87365,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -87391,7 +87391,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -87417,7 +87417,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -87443,7 +87443,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -87469,7 +87469,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -87495,7 +87495,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -87521,7 +87521,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -87547,7 +87547,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -87573,7 +87573,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -87599,7 +87599,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -87625,7 +87625,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87651,7 +87651,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -87677,7 +87677,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -87703,7 +87703,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -87729,7 +87729,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -87755,7 +87755,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -87781,7 +87781,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -87807,7 +87807,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -87833,7 +87833,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -87859,7 +87859,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -87885,7 +87885,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -87911,7 +87911,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -87937,7 +87937,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -87963,7 +87963,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -87989,7 +87989,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -88015,7 +88015,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -88041,7 +88041,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -88067,7 +88067,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -88093,7 +88093,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -88119,7 +88119,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -88145,7 +88145,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -88171,7 +88171,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -88197,7 +88197,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -88223,7 +88223,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -88249,7 +88249,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -88275,7 +88275,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -88301,7 +88301,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -88327,7 +88327,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -88353,7 +88353,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -88379,7 +88379,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -88405,7 +88405,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -88431,7 +88431,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -88457,7 +88457,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -88483,7 +88483,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -88509,7 +88509,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88535,7 +88535,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -88561,7 +88561,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -88587,7 +88587,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -88613,7 +88613,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -88639,7 +88639,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -88665,7 +88665,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -88691,7 +88691,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -88717,7 +88717,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -88743,7 +88743,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -88769,7 +88769,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -88795,7 +88795,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -88821,7 +88821,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -88847,7 +88847,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -88873,7 +88873,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -88899,7 +88899,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -88925,7 +88925,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -88951,7 +88951,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -88977,7 +88977,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -89003,7 +89003,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -89029,7 +89029,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -89055,7 +89055,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -89081,7 +89081,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -89107,7 +89107,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -89133,7 +89133,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -89159,7 +89159,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -89185,7 +89185,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -89211,7 +89211,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -89237,7 +89237,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -89263,7 +89263,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -89289,7 +89289,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89315,7 +89315,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -89341,7 +89341,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -89367,7 +89367,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -89473,7 +89473,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -89499,7 +89499,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 5.0, "wellLocation": { "offset": { @@ -89575,7 +89575,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -89601,7 +89601,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 10.0, "wellLocation": { "offset": { @@ -89677,7 +89677,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -89703,7 +89703,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -89779,7 +89779,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -89805,7 +89805,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -89881,7 +89881,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -89907,7 +89907,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -89983,7 +89983,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -90009,7 +90009,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -90085,7 +90085,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -90111,7 +90111,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 100.0, "wellLocation": { "offset": { @@ -90187,7 +90187,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -90213,7 +90213,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { @@ -90289,7 +90289,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90315,7 +90315,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -90391,7 +90391,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -90417,7 +90417,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -90493,7 +90493,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -90519,7 +90519,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 92.0, "wellLocation": { "offset": { @@ -90595,7 +90595,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -90621,7 +90621,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 88.0, "wellLocation": { "offset": { @@ -90697,7 +90697,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -90723,7 +90723,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -90799,7 +90799,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -90825,7 +90825,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -90901,7 +90901,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -90927,7 +90927,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -91003,7 +91003,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -91029,7 +91029,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 87.0, "wellLocation": { "offset": { @@ -91105,7 +91105,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -91131,7 +91131,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 82.0, "wellLocation": { "offset": { @@ -91207,7 +91207,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -91233,7 +91233,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 36.0, "wellLocation": { "offset": { @@ -91309,7 +91309,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -91335,7 +91335,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 78.0, "wellLocation": { "offset": { @@ -91411,7 +91411,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -91437,7 +91437,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -91513,7 +91513,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -91539,7 +91539,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -91615,7 +91615,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -91641,7 +91641,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 63.0, "wellLocation": { "offset": { @@ -91717,7 +91717,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -91743,7 +91743,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -91819,7 +91819,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -91845,7 +91845,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -91921,7 +91921,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -91947,7 +91947,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -92023,7 +92023,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -92049,7 +92049,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -92125,7 +92125,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -92151,7 +92151,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -92227,7 +92227,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -92253,7 +92253,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -92329,7 +92329,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -92355,7 +92355,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -92431,7 +92431,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -92457,7 +92457,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 52.0, "wellLocation": { "offset": { @@ -92533,7 +92533,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -92559,7 +92559,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -92635,7 +92635,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -92661,7 +92661,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -92737,7 +92737,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -92763,7 +92763,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 86.0, "wellLocation": { "offset": { @@ -92839,7 +92839,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -92865,7 +92865,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -92941,7 +92941,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -92967,7 +92967,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -93043,7 +93043,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -93069,7 +93069,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 96.0, "wellLocation": { "offset": { @@ -93145,7 +93145,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -93171,7 +93171,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 72.0, "wellLocation": { "offset": { @@ -93247,7 +93247,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -93273,7 +93273,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -93349,7 +93349,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -93375,7 +93375,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -93451,7 +93451,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -93477,7 +93477,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 41.0, "wellLocation": { "offset": { @@ -93553,7 +93553,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -93579,7 +93579,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -93655,7 +93655,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -93681,7 +93681,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -93757,7 +93757,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -93783,7 +93783,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -93859,7 +93859,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -93885,7 +93885,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -93961,7 +93961,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -93987,7 +93987,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 42.0, "wellLocation": { "offset": { @@ -94063,7 +94063,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -94089,7 +94089,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -94165,7 +94165,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -94191,7 +94191,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 48.0, "wellLocation": { "offset": { @@ -94267,7 +94267,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -94293,7 +94293,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 73.0, "wellLocation": { "offset": { @@ -94369,7 +94369,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -94395,7 +94395,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 84.0, "wellLocation": { "offset": { @@ -94471,7 +94471,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -94497,7 +94497,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -94573,7 +94573,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -94599,7 +94599,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 74.0, "wellLocation": { "offset": { @@ -94675,7 +94675,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -94701,7 +94701,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 80.0, "wellLocation": { "offset": { @@ -94777,7 +94777,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -94803,7 +94803,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -94879,7 +94879,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -94905,7 +94905,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -94981,7 +94981,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -95007,7 +95007,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -95083,7 +95083,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -95109,7 +95109,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -95185,7 +95185,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -95211,7 +95211,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 98.0, "wellLocation": { "offset": { @@ -95287,7 +95287,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -95313,7 +95313,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -95389,7 +95389,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -95415,7 +95415,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -95491,7 +95491,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -95517,7 +95517,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -95593,7 +95593,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -95619,7 +95619,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -95695,7 +95695,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95721,7 +95721,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -95797,7 +95797,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -95823,7 +95823,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -95899,7 +95899,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -95925,7 +95925,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 44.0, "wellLocation": { "offset": { @@ -96001,7 +96001,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -96027,7 +96027,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 89.0, "wellLocation": { "offset": { @@ -96103,7 +96103,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -96129,7 +96129,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -96205,7 +96205,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -96231,7 +96231,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 67.0, "wellLocation": { "offset": { @@ -96307,7 +96307,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -96333,7 +96333,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -96409,7 +96409,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -96435,7 +96435,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 79.0, "wellLocation": { "offset": { @@ -96511,7 +96511,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -96537,7 +96537,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -96613,7 +96613,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -96639,7 +96639,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 23.0, "wellLocation": { "offset": { @@ -96715,7 +96715,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -96741,7 +96741,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 26.0, "wellLocation": { "offset": { @@ -96817,7 +96817,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -96843,7 +96843,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -96919,7 +96919,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -96945,7 +96945,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -97021,7 +97021,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -97047,7 +97047,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 38.0, "wellLocation": { "offset": { @@ -97123,7 +97123,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -97149,7 +97149,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 99.0, "wellLocation": { "offset": { @@ -97225,7 +97225,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -97251,7 +97251,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 21.0, "wellLocation": { "offset": { @@ -97327,7 +97327,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -97353,7 +97353,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 59.0, "wellLocation": { "offset": { @@ -97429,7 +97429,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97455,7 +97455,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -97531,7 +97531,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -97557,7 +97557,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { @@ -97633,7 +97633,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -97659,7 +97659,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 28.0, "wellLocation": { "offset": { @@ -97735,7 +97735,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -97761,7 +97761,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 51.0, "wellLocation": { "offset": { @@ -97837,7 +97837,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -97863,7 +97863,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 34.0, "wellLocation": { "offset": { @@ -97939,7 +97939,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -97965,7 +97965,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 27.0, "wellLocation": { "offset": { @@ -98041,7 +98041,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -98067,7 +98067,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 60.0, "wellLocation": { "offset": { @@ -98143,7 +98143,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -98169,7 +98169,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 33.0, "wellLocation": { "offset": { @@ -98245,7 +98245,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -98271,7 +98271,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 61.0, "wellLocation": { "offset": { @@ -98347,7 +98347,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -98373,7 +98373,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 69.0, "wellLocation": { "offset": { @@ -98449,7 +98449,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -98475,7 +98475,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 47.0, "wellLocation": { "offset": { @@ -98551,7 +98551,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -98577,7 +98577,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 46.0, "wellLocation": { "offset": { @@ -98653,7 +98653,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -98679,7 +98679,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 93.0, "wellLocation": { "offset": { @@ -98755,7 +98755,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -98781,7 +98781,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 54.0, "wellLocation": { "offset": { @@ -98857,7 +98857,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -98883,7 +98883,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 65.0, "wellLocation": { "offset": { @@ -98959,7 +98959,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -98985,7 +98985,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 58.0, "wellLocation": { "offset": { @@ -99061,7 +99061,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -99087,7 +99087,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 37.0, "wellLocation": { "offset": { @@ -99144,7 +99144,7 @@ "errors": [], "files": [ { - "name": "Flex_P1000SRight_None_2_15_ABR_Simple_Normalize_Long_Right.py", + "name": "Flex_S_v2_15_P1000S_None_SimpleNormalizeLongRight.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0f31fd0836][OT2_P1000SLeft_None_6_1_SimpleTransfer].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[c064d0de2c][OT2_S_v6_P1000S_None_SimpleTransfer].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0f31fd0836][OT2_P1000SLeft_None_6_1_SimpleTransfer].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[c064d0de2c][OT2_S_v6_P1000S_None_SimpleTransfer].json index 044100d1a50..f42737b3020 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0f31fd0836][OT2_P1000SLeft_None_6_1_SimpleTransfer].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[c064d0de2c][OT2_S_v6_P1000S_None_SimpleTransfer].json @@ -1825,7 +1825,7 @@ "errors": [], "files": [ { - "name": "OT2_P1000SLeft_None_6_1_SimpleTransfer.json", + "name": "OT2_S_v6_P1000S_None_SimpleTransfer.json", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[695d29455b][OT2_None_None_TC_2_17_VerifyThermocyclerLoadedSlots].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[c195291f84][OT2_S_v2_17_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots].json similarity index 97% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[695d29455b][OT2_None_None_TC_2_17_VerifyThermocyclerLoadedSlots].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[c195291f84][OT2_S_v2_17_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots].json index 4b0477f0c6a..f2f2d4153be 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[695d29455b][OT2_None_None_TC_2_17_VerifyThermocyclerLoadedSlots].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[c195291f84][OT2_S_v2_17_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots].json @@ -127,7 +127,7 @@ "errors": [], "files": [ { - "name": "OT2_None_None_TC_2_17_VerifyThermocyclerLoadedSlots.py", + "name": "OT2_S_v2_17_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[8944a283da][Flex_None_None_TC_2_17_verifyThermocyclerLoadedSlots].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[c1c04baffd][Flex_S_v2_17_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots].json similarity index 95% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[8944a283da][Flex_None_None_TC_2_17_verifyThermocyclerLoadedSlots].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[c1c04baffd][Flex_S_v2_17_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots].json index 0568235766a..a04aaad78f3 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[8944a283da][Flex_None_None_TC_2_17_verifyThermocyclerLoadedSlots].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[c1c04baffd][Flex_S_v2_17_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots].json @@ -137,7 +137,7 @@ "errorInfo": { "args": "()", "class": "AssertionError", - "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_None_None_TC_2_17_verifyThermocyclerLoadedSlots.py\", line 13, in run\n" + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_S_v2_17_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots.py\", line 13, in run\n" }, "errorType": "PythonException", "wrappedErrors": [] @@ -147,7 +147,7 @@ ], "files": [ { - "name": "Flex_None_None_TC_2_17_verifyThermocyclerLoadedSlots.py", + "name": "Flex_S_v2_17_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[69f47f8bcc][OT2_None_None_TC_2_15_VerifyThermocyclerLoadedSlots].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[c3098303ad][OT2_S_v2_15_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots].json similarity index 98% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[69f47f8bcc][OT2_None_None_TC_2_15_VerifyThermocyclerLoadedSlots].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[c3098303ad][OT2_S_v2_15_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots].json index b81d62a94d8..3c4cb61561e 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[69f47f8bcc][OT2_None_None_TC_2_15_VerifyThermocyclerLoadedSlots].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[c3098303ad][OT2_S_v2_15_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots].json @@ -127,7 +127,7 @@ "errors": [], "files": [ { - "name": "OT2_None_None_TC_2_15_VerifyThermocyclerLoadedSlots.py", + "name": "OT2_S_v2_15_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[2a32a763f5][Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoModules].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[c745e5824a][Flex_S_v2_16_P1000_96_GRIP_DeckConfiguration1NoModules].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[2a32a763f5][Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoModules].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[c745e5824a][Flex_S_v2_16_P1000_96_GRIP_DeckConfiguration1NoModules].json index 7dc9a75b76e..ee20acd85cd 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[2a32a763f5][Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoModules].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[c745e5824a][Flex_S_v2_16_P1000_96_GRIP_DeckConfiguration1NoModules].json @@ -10629,7 +10629,7 @@ "notes": [], "params": { "addressableAreaName": "movableTrashC1", - "alternateDropLocation": false, + "alternateDropLocation": true, "forceDirect": false, "ignoreTipConfiguration": true, "offset": { @@ -10640,7 +10640,7 @@ }, "result": { "position": { - "x": 22.25, + "x": 54.25, "y": 150.0, "z": 40.0 } @@ -10888,7 +10888,7 @@ "notes": [], "params": { "addressableAreaName": "movableTrashD1", - "alternateDropLocation": false, + "alternateDropLocation": true, "forceDirect": false, "ignoreTipConfiguration": true, "offset": { @@ -10899,7 +10899,7 @@ }, "result": { "position": { - "x": 22.25, + "x": 54.25, "y": 43.0, "z": 40.0 } @@ -11206,7 +11206,7 @@ "errors": [], "files": [ { - "name": "Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1_NoModules.py", + "name": "Flex_S_v2_16_P1000_96_GRIP_DeckConfiguration1NoModules.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6258435dc4][OT2_P300M_P20S_TC_MM_TM_2_13_Smoke620Release].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[c821e64fad][OT2_S_v2_13_P300M_P20S_MM_TC_TM_Smoke620Release].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6258435dc4][OT2_P300M_P20S_TC_MM_TM_2_13_Smoke620Release].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[c821e64fad][OT2_S_v2_13_P300M_P20S_MM_TC_TM_Smoke620Release].json index b6c92f8526c..47f9ac631a6 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6258435dc4][OT2_P300M_P20S_TC_MM_TM_2_13_Smoke620Release].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[c821e64fad][OT2_S_v2_13_P300M_P20S_MM_TC_TM_Smoke620Release].json @@ -9834,7 +9834,7 @@ "errors": [], "files": [ { - "name": "OT2_P300M_P20S_TC_MM_TM_2_13_Smoke620Release.py", + "name": "OT2_S_v2_13_P300M_P20S_MM_TC_TM_Smoke620Release.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4835239037][OT2_P300M_P20S_MM_TM_TC1_5_2_6_PD40Error].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[c9e6e3d59d][OT2_X_v4_P300M_P20S_MM_TC1_TM_e2eTests].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4835239037][OT2_P300M_P20S_MM_TM_TC1_5_2_6_PD40Error].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[c9e6e3d59d][OT2_X_v4_P300M_P20S_MM_TC1_TM_e2eTests].json index 636e3ae1cbc..ea5794cc6a8 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[4835239037][OT2_P300M_P20S_MM_TM_TC1_5_2_6_PD40Error].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[c9e6e3d59d][OT2_X_v4_P300M_P20S_MM_TC1_TM_e2eTests].json @@ -6924,7 +6924,7 @@ "errorInfo": { "args": "('Cannot aspirate more than pipette max volume',)", "class": "AssertionError", - "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/legacy_commands/publisher.py\", line 113, in publish_context\n yield\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line 270, in aspirate\n self._core.aspirate(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py\", line 119, in aspirate\n new_volume <= self._pipette_dict[\"working_volume\"]\n" + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/legacy_commands/publisher.py\", line 113, in publish_context\n yield\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line 272, in aspirate\n self._core.aspirate(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py\", line 119, in aspirate\n new_volume <= self._pipette_dict[\"working_volume\"]\n" }, "errorType": "PythonException", "wrappedErrors": [] @@ -6965,7 +6965,7 @@ "errorInfo": { "args": "('Cannot aspirate more than pipette max volume',)", "class": "AssertionError", - "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_runner/task_queue.py\", line 84, in _run\n await self._run_func()\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_runner/task_queue.py\", line 61, in _do_run\n await func(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_runner/protocol_runner.py\", line 219, in run_func\n await self._legacy_executor.execute(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_runner/legacy_wrappers.py\", line 180, in execute\n await to_thread.run_sync(\n\n File \"/usr/local/lib/python3.10/site-packages/anyio/to_thread.py\", line 33, in run_sync\n return await get_asynclib().run_sync_in_worker_thread(\n\n File \"/usr/local/lib/python3.10/site-packages/anyio/_backends/_asyncio.py\", line 877, in run_sync_in_worker_thread\n return await future\n\n File \"/usr/local/lib/python3.10/site-packages/anyio/_backends/_asyncio.py\", line 807, in run\n result = context.run(func, *args)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute.py\", line 63, in run_protocol\n execute_json_v4.dispatch_json(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_json_v4.py\", line 272, in dispatch_json\n pipette_command_map[command_type]( # type: ignore\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_json_v3.py\", line 159, in _aspirate\n pipette.aspirate(volume, location)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line 383, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line 270, in aspirate\n self._core.aspirate(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py\", line 119, in aspirate\n new_volume <= self._pipette_dict[\"working_volume\"]\n" + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_runner/task_queue.py\", line 84, in _run\n await self._run_func()\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_runner/task_queue.py\", line 61, in _do_run\n await func(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_runner/protocol_runner.py\", line 219, in run_func\n await self._legacy_executor.execute(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_runner/legacy_wrappers.py\", line 180, in execute\n await to_thread.run_sync(\n\n File \"/usr/local/lib/python3.10/site-packages/anyio/to_thread.py\", line 33, in run_sync\n return await get_asynclib().run_sync_in_worker_thread(\n\n File \"/usr/local/lib/python3.10/site-packages/anyio/_backends/_asyncio.py\", line 877, in run_sync_in_worker_thread\n return await future\n\n File \"/usr/local/lib/python3.10/site-packages/anyio/_backends/_asyncio.py\", line 807, in run\n result = context.run(func, *args)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute.py\", line 63, in run_protocol\n execute_json_v4.dispatch_json(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_json_v4.py\", line 272, in dispatch_json\n pipette_command_map[command_type]( # type: ignore\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_json_v3.py\", line 159, in _aspirate\n pipette.aspirate(volume, location)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line 383, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line 272, in aspirate\n self._core.aspirate(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py\", line 119, in aspirate\n new_volume <= self._pipette_dict[\"working_volume\"]\n" }, "errorType": "PythonException", "wrappedErrors": [] @@ -6975,7 +6975,7 @@ ], "files": [ { - "name": "OT2_P300M_P20S_MM_TM_TC1_5_2_6_PD40Error.json", + "name": "OT2_X_v4_P300M_P20S_MM_TC1_TM_e2eTests.json", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6b4d75cb04][OT2_P20S_P300M_NoMods_6_1_TransferReTransferLiquid].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[cb5adc3d23][OT2_S_v6_P20S_P300M_TransferReTransferLiquid].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6b4d75cb04][OT2_P20S_P300M_NoMods_6_1_TransferReTransferLiquid].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[cb5adc3d23][OT2_S_v6_P20S_P300M_TransferReTransferLiquid].json index 36e8ee71f89..70e67b94ed3 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[6b4d75cb04][OT2_P20S_P300M_NoMods_6_1_TransferReTransferLiquid].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[cb5adc3d23][OT2_S_v6_P20S_P300M_TransferReTransferLiquid].json @@ -10674,7 +10674,7 @@ "errors": [], "files": [ { - "name": "OT2_P20S_P300M_NoMods_6_1_TransferReTransferLiquid.json", + "name": "OT2_S_v6_P20S_P300M_TransferReTransferLiquid.json", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[cda954ef1e][Flex_None_None_MM_2_16_AnalysisError_MagneticModuleInFlexProtocol].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[cda954ef1e][Flex_None_None_MM_2_16_AnalysisError_MagneticModuleInFlexProtocol].json deleted file mode 100644 index d88dc1e3bc9..00000000000 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[cda954ef1e][Flex_None_None_MM_2_16_AnalysisError_MagneticModuleInFlexProtocol].json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "commands": [ - { - "commandType": "home", - "notes": [], - "params": {}, - "result": {}, - "status": "succeeded" - } - ], - "config": { - "apiVersion": [ - 2, - 16 - ], - "protocolType": "python" - }, - "errors": [ - { - "detail": "ValueError [line 15]: A magneticModuleType cannot be loaded into slot C1", - "errorCode": "4000", - "errorInfo": {}, - "errorType": "ExceptionInProtocolError", - "wrappedErrors": [ - { - "detail": "ValueError: A magneticModuleType cannot be loaded into slot C1", - "errorCode": "4000", - "errorInfo": { - "args": "('A magneticModuleType cannot be loaded into slot C1',)", - "class": "ValueError", - "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_None_None_MM_2_16_AnalysisError_MagneticModuleInFlexProtocol.py\", line 15, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line 383, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/protocol_context.py\", line 814, in load_module\n module_core = self._core.load_module(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/engine/protocol.py\", line 412, in load_module\n self._ensure_module_location(normalized_deck_slot, module_type)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/engine/protocol.py\", line 631, in _ensure_module_location\n raise ValueError(f\"A {module_type.value} cannot be loaded into slot {slot}\")\n" - }, - "errorType": "PythonException", - "wrappedErrors": [] - } - ] - } - ], - "files": [ - { - "name": "Flex_None_None_MM_2_16_AnalysisError_MagneticModuleInFlexProtocol.py", - "role": "main" - }, - { - "name": "cpx_4_tuberack_100ul.json", - "role": "labware" - }, - { - "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", - "role": "labware" - }, - { - "name": "opentrons_ot3_96_tiprack_200ul_rss.json", - "role": "labware" - }, - { - "name": "opentrons_ot3_96_tiprack_50ul_rss.json", - "role": "labware" - }, - { - "name": "sample_labware.json", - "role": "labware" - } - ], - "labware": [], - "liquids": [], - "metadata": { - "author": "Derek Maggio ", - "protocolName": "QA Protocol - Analysis Error - Magnetic Module in Flex Protocol" - }, - "modules": [], - "pipettes": [], - "robotType": "OT-3 Standard", - "runTimeParameters": [] -} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[ce0f35b3c6][Flex_None_None_TM_2_16_AnalysisError_ModuleInCol2].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[ce0f35b3c6][Flex_None_None_TM_2_16_AnalysisError_ModuleInCol2].json deleted file mode 100644 index 9f85e6ecdcb..00000000000 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[ce0f35b3c6][Flex_None_None_TM_2_16_AnalysisError_ModuleInCol2].json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "commands": [ - { - "commandType": "home", - "notes": [], - "params": {}, - "result": {}, - "status": "succeeded" - } - ], - "config": { - "apiVersion": [ - 2, - 16 - ], - "protocolType": "python" - }, - "errors": [ - { - "detail": "ValueError [line 15]: A temperatureModuleType cannot be loaded into slot C2", - "errorCode": "4000", - "errorInfo": {}, - "errorType": "ExceptionInProtocolError", - "wrappedErrors": [ - { - "detail": "ValueError: A temperatureModuleType cannot be loaded into slot C2", - "errorCode": "4000", - "errorInfo": { - "args": "('A temperatureModuleType cannot be loaded into slot C2',)", - "class": "ValueError", - "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_None_None_TM_2_16_AnalysisError_ModuleInCol2.py\", line 15, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line 383, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/protocol_context.py\", line 814, in load_module\n module_core = self._core.load_module(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/engine/protocol.py\", line 412, in load_module\n self._ensure_module_location(normalized_deck_slot, module_type)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/engine/protocol.py\", line 631, in _ensure_module_location\n raise ValueError(f\"A {module_type.value} cannot be loaded into slot {slot}\")\n" - }, - "errorType": "PythonException", - "wrappedErrors": [] - } - ] - } - ], - "files": [ - { - "name": "Flex_None_None_TM_2_16_AnalysisError_ModuleInCol2.py", - "role": "main" - }, - { - "name": "cpx_4_tuberack_100ul.json", - "role": "labware" - }, - { - "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", - "role": "labware" - }, - { - "name": "opentrons_ot3_96_tiprack_200ul_rss.json", - "role": "labware" - }, - { - "name": "opentrons_ot3_96_tiprack_50ul_rss.json", - "role": "labware" - }, - { - "name": "sample_labware.json", - "role": "labware" - } - ], - "labware": [], - "liquids": [], - "metadata": { - "author": "Derek Maggio ", - "protocolName": "QA Protocol - Analysis Error - Module in Column 2" - }, - "modules": [], - "pipettes": [], - "robotType": "OT-3 Standard", - "runTimeParameters": [] -} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f91ecb541c][OT2_P300M_P20S_TC_HS_TM_2_17_SmokeTestV3].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[d48bc4f0c9][OT2_S_v2_17_P300M_P20S_HS_TC_TM_SmokeTestV3].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f91ecb541c][OT2_P300M_P20S_TC_HS_TM_2_17_SmokeTestV3].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[d48bc4f0c9][OT2_S_v2_17_P300M_P20S_HS_TC_TM_SmokeTestV3].json index 0245a572ca9..d2a73ab17e9 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f91ecb541c][OT2_P300M_P20S_TC_HS_TM_2_17_SmokeTestV3].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[d48bc4f0c9][OT2_S_v2_17_P300M_P20S_HS_TC_TM_SmokeTestV3].json @@ -15549,7 +15549,7 @@ "errors": [], "files": [ { - "name": "OT2_P300M_P20S_TC_HS_TM_2_17_SmokeTestV3.py", + "name": "OT2_S_v2_17_P300M_P20S_HS_TC_TM_SmokeTestV3.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[78960c4c8e][OT2_P300S_Twinning_Error].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[d6026e11c5][OT2_X_v2_7_P300S_TwinningError].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[78960c4c8e][OT2_P300S_Twinning_Error].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[d6026e11c5][OT2_X_v2_7_P300S_TwinningError].json index 07585c1c1c7..a67595aa67c 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[78960c4c8e][OT2_P300S_Twinning_Error].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[d6026e11c5][OT2_X_v2_7_P300S_TwinningError].json @@ -2714,7 +2714,7 @@ "class": "AttributeError", "name": "pair_with", "obj": "P300 Single-Channel GEN2 on left mount", - "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"OT2_P300S_Twinning_Error.py\", line 23, in run\n" + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"OT2_X_v2_7_P300S_TwinningError.py\", line 23, in run\n" }, "errorType": "PythonException", "wrappedErrors": [] @@ -2724,7 +2724,7 @@ ], "files": [ { - "name": "OT2_P300S_Twinning_Error.py", + "name": "OT2_X_v2_7_P300S_TwinningError.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[d7e862d601][OT2_S_v2_18_None_None_duplicateChoiceValue].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[d7e862d601][OT2_S_v2_18_None_None_duplicateChoiceValue].json new file mode 100644 index 00000000000..792ce852c07 --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[d7e862d601][OT2_S_v2_18_None_None_duplicateChoiceValue].json @@ -0,0 +1,87 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "custom", + "notes": [], + "params": { + "legacyCommandText": "variable pipette has value flex_1channel_50", + "legacyCommandType": "command.COMMENT" + }, + "result": {}, + "status": "succeeded" + } + ], + "config": { + "apiVersion": [ + 2, + 18 + ], + "protocolType": "python" + }, + "errors": [], + "files": [ + { + "name": "OT2_S_v2_18_None_None_duplicateChoiceValue.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "protocolName": "Duplicate choice value" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-2 Standard", + "runTimeParameters": [ + { + "choices": [ + { + "displayName": "Single channel 50µL", + "value": "flex_1channel_50" + }, + { + "displayName": "Eight Channel 50µL", + "value": "flex_8channel_50" + }, + { + "displayName": "Single channel 50µL again", + "value": "flex_1channel_50" + } + ], + "default": "flex_1channel_50", + "description": "What pipette to use during the protocol.", + "displayName": "Pipette Name", + "type": "str", + "value": "flex_1channel_50", + "variableName": "pipette" + } + ] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[7840348786][Flex_P1000_96_TC_2_16_PartialTipPickupSingle].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[d8cb88b3b2][Flex_S_v2_16_P1000_96_TC_PartialTipPickupSingle].json similarity index 97% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[7840348786][Flex_P1000_96_TC_2_16_PartialTipPickupSingle].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[d8cb88b3b2][Flex_S_v2_16_P1000_96_TC_PartialTipPickupSingle].json index 79f4230779e..bcd9c895119 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[7840348786][Flex_P1000_96_TC_2_16_PartialTipPickupSingle].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[d8cb88b3b2][Flex_S_v2_16_P1000_96_TC_PartialTipPickupSingle].json @@ -2,12 +2,14 @@ "commands": [ { "commandType": "home", + "notes": [], "params": {}, "result": {}, "status": "succeeded" }, { "commandType": "loadLabware", + "notes": [], "params": { "loadName": "opentrons_flex_96_tiprack_50ul", "location": { @@ -1159,6 +1161,7 @@ }, { "commandType": "loadPipette", + "notes": [], "params": { "mount": "left", "pipetteName": "p1000_96" @@ -1168,6 +1171,7 @@ }, { "commandType": "loadLabware", + "notes": [], "params": { "loadName": "nest_96_wellplate_200ul_flat", "location": { @@ -2328,6 +2332,7 @@ }, { "commandType": "loadLabware", + "notes": [], "params": { "loadName": "nest_96_wellplate_200ul_flat", "location": { @@ -3485,120 +3490,6 @@ } }, "status": "succeeded" - }, - { - "commandType": "configureNozzleLayout", - "params": { - "configurationParams": { - "primaryNozzle": "H12", - "style": "SINGLE" - } - }, - "result": {}, - "status": "succeeded" - }, - { - "commandType": "pickUpTip", - "params": { - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "origin": "top" - }, - "wellName": "A2" - }, - "result": { - "position": { - "x": 351.38, - "y": 181.38, - "z": 99.0 - }, - "tipDiameter": 5.58, - "tipLength": 47.4, - "tipVolume": 50.0 - }, - "status": "succeeded" - }, - { - "commandType": "aspirate", - "params": { - "flowRate": 160.0, - "volume": 50.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -9.8 - }, - "origin": "top" - }, - "wellName": "E4" - }, - "result": { - "position": { - "x": 205.28, - "y": 145.18, - "z": 4.5 - }, - "volume": 50.0 - }, - "status": "succeeded" - }, - { - "commandType": "dispense", - "params": { - "flowRate": 160.0, - "volume": 20.0, - "wellLocation": { - "offset": { - "x": 0.0, - "y": 0.0, - "z": -9.8 - }, - "origin": "top" - }, - "wellName": "B5" - }, - "result": { - "position": { - "x": 50.28, - "y": 172.18, - "z": 4.5 - }, - "volume": 20.0 - }, - "status": "succeeded" - }, - { - "commandType": "moveToAddressableAreaForDropTip", - "params": { - "addressableAreaName": "movableTrashA3", - "alternateDropLocation": true, - "forceDirect": false, - "ignoreTipConfiguration": true, - "offset": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - } - }, - "result": { - "position": { - "x": 466.25, - "y": 364.0, - "z": 40.0 - } - }, - "status": "succeeded" - }, - { - "commandType": "dropTipInPlace", - "params": {}, - "result": {}, - "status": "succeeded" } ], "config": { @@ -3608,10 +3499,30 @@ ], "protocolType": "python" }, - "errors": [], + "errors": [ + { + "detail": "ValueError [line 16]: Nozzle layout configuration of style SINGLE is currently unsupported.", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ExceptionInProtocolError", + "wrappedErrors": [ + { + "detail": "ValueError: Nozzle layout configuration of style SINGLE is currently unsupported.", + "errorCode": "4000", + "errorInfo": { + "args": "('Nozzle layout configuration of style SINGLE is currently unsupported.',)", + "class": "ValueError", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_S_v2_16_P1000_96_TC_PartialTipPickupSingle.py\", line 16, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line 383, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line 1961, in configure_nozzle_layout\n raise ValueError(\n" + }, + "errorType": "PythonException", + "wrappedErrors": [] + } + ] + } + ], "files": [ { - "name": "Flex_P1000_96_TC_2_16_PartialTipPickupSingle.py", + "name": "Flex_S_v2_16_P1000_96_TC_PartialTipPickupSingle.py", "role": "main" }, { @@ -3667,5 +3578,6 @@ "pipetteName": "p1000_96" } ], - "robotType": "OT-3 Standard" + "robotType": "OT-3 Standard", + "runTimeParameters": [] } diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[caee1acfad][OT2_None_None_TC_2_16_VerifyThermocyclerLoadedSlots].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[dbba7a71a8][OT2_S_v2_16_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots].json similarity index 97% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[caee1acfad][OT2_None_None_TC_2_16_VerifyThermocyclerLoadedSlots].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[dbba7a71a8][OT2_S_v2_16_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots].json index 3182743836c..4b308445002 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[caee1acfad][OT2_None_None_TC_2_16_VerifyThermocyclerLoadedSlots].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[dbba7a71a8][OT2_S_v2_16_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots].json @@ -127,7 +127,7 @@ "errors": [], "files": [ { - "name": "OT2_None_None_TC_2_16_VerifyThermocyclerLoadedSlots.py", + "name": "OT2_S_v2_16_NO_PIPETTES_TC_VerifyThermocyclerLoadedSlots.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[5931902632][Flex_None_None_TC_2_16_AnalysisError_TrashBinAndThermocyclerConflict].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[de4249ddfb][Flex_X_v2_16_NO_PIPETTES_TC_TrashBinAndThermocyclerConflict].json similarity index 78% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[5931902632][Flex_None_None_TC_2_16_AnalysisError_TrashBinAndThermocyclerConflict].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[de4249ddfb][Flex_X_v2_16_NO_PIPETTES_TC_TrashBinAndThermocyclerConflict].json index 65d49f5fb6b..e367d7faa2d 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[5931902632][Flex_None_None_TC_2_16_AnalysisError_TrashBinAndThermocyclerConflict].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[de4249ddfb][Flex_X_v2_16_NO_PIPETTES_TC_TrashBinAndThermocyclerConflict].json @@ -137,7 +137,7 @@ "errorInfo": { "args": "('thermocyclerModuleV2 in slot B1 prevents trash bin from using slot A1.',)", "class": "DeckConflictError", - "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_None_None_TC_2_16_AnalysisError_TrashBinAndThermocyclerConflict.py\", line 13, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line 383, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/protocol_context.py\", line 518, in load_trash_bin\n trash_bin = self._core.load_trash_bin(slot_name, addressable_area_name)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/engine/protocol.py\", line 529, in load_trash_bin\n self._add_disposal_location_to_engine(trash_bin)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/engine/protocol.py\", line 148, in _add_disposal_location_to_engine\n deck_conflict.check(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/engine/deck_conflict.py\", line 203, in check\n wrapped_deck_conflict.check(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/motion_planning/deck_conflict.py\", line 210, in check\n raise DeckConflictError(\n" + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_X_v2_16_NO_PIPETTES_TC_TrashBinAndThermocyclerConflict.py\", line 13, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line 383, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/protocol_context.py\", line 518, in load_trash_bin\n trash_bin = self._core.load_trash_bin(slot_name, addressable_area_name)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/engine/protocol.py\", line 528, in load_trash_bin\n self._add_disposal_location_to_engine(trash_bin)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/engine/protocol.py\", line 148, in _add_disposal_location_to_engine\n deck_conflict.check(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/core/engine/deck_conflict.py\", line 203, in check\n wrapped_deck_conflict.check(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/motion_planning/deck_conflict.py\", line 210, in check\n raise DeckConflictError(\n" }, "errorType": "PythonException", "wrappedErrors": [] @@ -147,7 +147,7 @@ ], "files": [ { - "name": "Flex_None_None_TC_2_16_AnalysisError_TrashBinAndThermocyclerConflict.py", + "name": "Flex_X_v2_16_NO_PIPETTES_TC_TrashBinAndThermocyclerConflict.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[53e75c4553][Flex_P1000_96_HS_TM_MM_2_15_ABR5_6_HDQ_Bacteria_ParkTips_96_channel].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[de842b7217][Flex_S_v2_15_P1000_96_GRIP_HS_MB_TM_OmegaHDQDNAExtraction].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[53e75c4553][Flex_P1000_96_HS_TM_MM_2_15_ABR5_6_HDQ_Bacteria_ParkTips_96_channel].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[de842b7217][Flex_S_v2_15_P1000_96_GRIP_HS_MB_TM_OmegaHDQDNAExtraction].json index 0ea18a09995..c9208c66d22 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[53e75c4553][Flex_P1000_96_HS_TM_MM_2_15_ABR5_6_HDQ_Bacteria_ParkTips_96_channel].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[de842b7217][Flex_S_v2_15_P1000_96_GRIP_HS_MB_TM_OmegaHDQDNAExtraction].json @@ -13337,7 +13337,7 @@ ], "files": [ { - "name": "Flex_P1000_96_HS_TM_MM_2_15_ABR5_6_HDQ_Bacteria_ParkTips_96_channel.py", + "name": "Flex_S_v2_15_P1000_96_GRIP_HS_MB_TM_OmegaHDQDNAExtraction.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[753ac8811f][OT2_None_None_2_13_PythonSyntaxError].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[e42e36e3ca][OT2_X_v2_13_None_None_PythonSyntaxError].json similarity index 95% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[753ac8811f][OT2_None_None_2_13_PythonSyntaxError].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[e42e36e3ca][OT2_X_v2_13_None_None_PythonSyntaxError].json index af560dfb9f3..7e05bcc5181 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[753ac8811f][OT2_None_None_2_13_PythonSyntaxError].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[e42e36e3ca][OT2_X_v2_13_None_None_PythonSyntaxError].json @@ -31,7 +31,7 @@ "msg": "No module named 'superspecialmagic'", "name": "superspecialmagic", "path": "None", - "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_runner/task_queue.py\", line 84, in _run\n await self._run_func()\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_runner/task_queue.py\", line 61, in _do_run\n await func(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_runner/protocol_runner.py\", line 219, in run_func\n await self._legacy_executor.execute(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_runner/legacy_wrappers.py\", line 180, in execute\n await to_thread.run_sync(\n\n File \"/usr/local/lib/python3.10/site-packages/anyio/to_thread.py\", line 33, in run_sync\n return await get_asynclib().run_sync_in_worker_thread(\n\n File \"/usr/local/lib/python3.10/site-packages/anyio/_backends/_asyncio.py\", line 877, in run_sync_in_worker_thread\n return await future\n\n File \"/usr/local/lib/python3.10/site-packages/anyio/_backends/_asyncio.py\", line 807, in run\n result = context.run(func, *args)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute.py\", line 40, in run_protocol\n run_python(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 95, in run_python\n exec(proto.contents, new_globs)\n\n File \"OT2_None_None_2_13_PythonSyntaxError.py\", line 4, in \n" + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_runner/task_queue.py\", line 84, in _run\n await self._run_func()\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_runner/task_queue.py\", line 61, in _do_run\n await func(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_runner/protocol_runner.py\", line 219, in run_func\n await self._legacy_executor.execute(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_runner/legacy_wrappers.py\", line 180, in execute\n await to_thread.run_sync(\n\n File \"/usr/local/lib/python3.10/site-packages/anyio/to_thread.py\", line 33, in run_sync\n return await get_asynclib().run_sync_in_worker_thread(\n\n File \"/usr/local/lib/python3.10/site-packages/anyio/_backends/_asyncio.py\", line 877, in run_sync_in_worker_thread\n return await future\n\n File \"/usr/local/lib/python3.10/site-packages/anyio/_backends/_asyncio.py\", line 807, in run\n result = context.run(func, *args)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute.py\", line 40, in run_protocol\n run_python(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 95, in run_python\n exec(proto.contents, new_globs)\n\n File \"OT2_X_v2_13_None_None_PythonSyntaxError.py\", line 4, in \n" }, "errorType": "PythonException", "wrappedErrors": [] @@ -41,7 +41,7 @@ ], "files": [ { - "name": "OT2_None_None_2_13_PythonSyntaxError.py", + "name": "OT2_X_v2_13_None_None_PythonSyntaxError.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[5635695ed6][OT2_P300SLeft_MM_TM_TM_5_2_6_MOAMTemps].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[e4660ca6df][OT2_S_v4_P300S_None_MM_TM_TM_MOAMTemps].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[5635695ed6][OT2_P300SLeft_MM_TM_TM_5_2_6_MOAMTemps].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[e4660ca6df][OT2_S_v4_P300S_None_MM_TM_TM_MOAMTemps].json index 03d82f46aea..e6aadeb2fca 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[5635695ed6][OT2_P300SLeft_MM_TM_TM_5_2_6_MOAMTemps].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[e4660ca6df][OT2_S_v4_P300S_None_MM_TM_TM_MOAMTemps].json @@ -2469,7 +2469,7 @@ "errors": [], "files": [ { - "name": "OT2_P300SLeft_MM_TM_TM_5_2_6_MOAMTemps.json", + "name": "OT2_S_v4_P300S_None_MM_TM_TM_MOAMTemps.json", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[e496fec176][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_default].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[e496fec176][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_default].json new file mode 100644 index 00000000000..4bb8dc2ba41 --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[e496fec176][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_default].json @@ -0,0 +1,74 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + } + ], + "config": { + "apiVersion": [ + 2, + 18 + ], + "protocolType": "python" + }, + "errors": [ + { + "detail": "ParameterValueError [line 73]: Parameter default 6 has type 'int', but must be of type 'str'.", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ExceptionInProtocolError", + "wrappedErrors": [ + { + "detail": "opentrons.protocols.parameters.types.ParameterValueError: Parameter default 6 has type 'int', but must be of type 'str'.", + "errorCode": "4000", + "errorInfo": { + "args": "(\"Parameter default 6 has type 'int', but must be of type 'str'.\",)", + "class": "ParameterValueError", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 80, in _parse_and_set_parameters\n exec(\"add_parameters(__param_context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_default.py\", line 73, in add_parameters\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/_parameter_context.py\", line 152, in add_str\n parameter = parameter_definition.create_str_parameter(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 241, in create_str_parameter\n return ParameterDefinition(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 73, in __init__\n validation.validate_options(default, minimum, maximum, choices, parameter_type)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/validation.py\", line 253, in validate_options\n raise ParameterValueError(\n" + }, + "errorType": "PythonException", + "wrappedErrors": [] + } + ] + } + ], + "files": [ + { + "name": "Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_default.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "protocolName": "Description Too Long 2.18" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-3 Standard", + "runTimeParameters": [] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0400decc88][Flex_P1000MLeft_P50MRight_HS_TM_MM_TC_2_15_ABR4_Illumina_DNA_Prep_24x].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[e907467039][Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAPrep24x].json similarity index 96% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0400decc88][Flex_P1000MLeft_P50MRight_HS_TM_MM_TC_2_15_ABR4_Illumina_DNA_Prep_24x].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[e907467039][Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAPrep24x].json index d321c3f1579..48382e2d0ac 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[0400decc88][Flex_P1000MLeft_P50MRight_HS_TM_MM_TC_2_15_ABR4_Illumina_DNA_Prep_24x].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[e907467039][Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAPrep24x].json @@ -8325,7 +8325,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -8351,7 +8351,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -8377,7 +8377,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -8403,7 +8403,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -8429,7 +8429,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -8455,7 +8455,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -8481,7 +8481,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 20.0, "wellLocation": { "offset": { @@ -8507,13 +8507,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 20.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -8538,7 +8538,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -11.280000000000001 + "z": -11.279999999999998 }, "origin": "top" }, @@ -8557,13 +8557,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 40.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -11.280000000000001 + "z": -11.279999999999998 }, "origin": "top" }, @@ -8588,7 +8588,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -8607,13 +8607,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 20.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -8633,13 +8633,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 20.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -8664,7 +8664,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -11.280000000000001 + "z": -11.279999999999998 }, "origin": "top" }, @@ -8683,13 +8683,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 40.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -11.280000000000001 + "z": -11.279999999999998 }, "origin": "top" }, @@ -8709,13 +8709,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 40.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -11.280000000000001 + "z": -11.279999999999998 }, "origin": "top" }, @@ -8740,7 +8740,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -8759,13 +8759,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 20.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -8785,13 +8785,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 20.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -8816,7 +8816,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -11.280000000000001 + "z": -11.279999999999998 }, "origin": "top" }, @@ -8835,13 +8835,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 40.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -11.280000000000001 + "z": -11.279999999999998 }, "origin": "top" }, @@ -8861,12 +8861,12 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": 2.0 + "z": 2.000000000000007 }, "origin": "top" }, @@ -8890,7 +8890,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -8924,7 +8924,7 @@ "position": { "x": 14.38, "y": 74.24, - "z": 34.650000000000006 + "z": 34.65 } }, "status": "succeeded" @@ -8938,7 +8938,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -9007,7 +9007,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -9033,7 +9033,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -9059,7 +9059,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -9085,7 +9085,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -9111,7 +9111,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -9137,7 +9137,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -9163,7 +9163,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 20.0, "wellLocation": { "offset": { @@ -9189,13 +9189,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 20.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -9220,7 +9220,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -11.280000000000001 + "z": -11.279999999999998 }, "origin": "top" }, @@ -9239,13 +9239,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 40.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -11.280000000000001 + "z": -11.279999999999998 }, "origin": "top" }, @@ -9270,7 +9270,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -9289,13 +9289,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 20.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -9315,13 +9315,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 20.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -9346,7 +9346,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -11.280000000000001 + "z": -11.279999999999998 }, "origin": "top" }, @@ -9365,13 +9365,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 40.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -11.280000000000001 + "z": -11.279999999999998 }, "origin": "top" }, @@ -9391,13 +9391,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 40.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -11.280000000000001 + "z": -11.279999999999998 }, "origin": "top" }, @@ -9422,7 +9422,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -9441,13 +9441,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 20.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -9467,13 +9467,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 20.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -9498,7 +9498,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -11.280000000000001 + "z": -11.279999999999998 }, "origin": "top" }, @@ -9517,13 +9517,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 40.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -11.280000000000001 + "z": -11.279999999999998 }, "origin": "top" }, @@ -9543,12 +9543,12 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": 2.0 + "z": 2.000000000000007 }, "origin": "top" }, @@ -9572,7 +9572,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -9606,7 +9606,7 @@ "position": { "x": 23.38, "y": 74.24, - "z": 34.650000000000006 + "z": 34.65 } }, "status": "succeeded" @@ -9620,7 +9620,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -9689,7 +9689,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -9715,7 +9715,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -9741,7 +9741,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -9767,7 +9767,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -9793,7 +9793,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -9819,7 +9819,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 30.0, "wellLocation": { "offset": { @@ -9845,7 +9845,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 20.0, "wellLocation": { "offset": { @@ -9871,13 +9871,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 20.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -9902,7 +9902,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -11.280000000000001 + "z": -11.279999999999998 }, "origin": "top" }, @@ -9921,13 +9921,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 40.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -11.280000000000001 + "z": -11.279999999999998 }, "origin": "top" }, @@ -9952,7 +9952,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -9971,13 +9971,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 20.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -9997,13 +9997,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 20.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -10028,7 +10028,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -11.280000000000001 + "z": -11.279999999999998 }, "origin": "top" }, @@ -10047,13 +10047,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 40.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -11.280000000000001 + "z": -11.279999999999998 }, "origin": "top" }, @@ -10073,13 +10073,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 40.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -11.280000000000001 + "z": -11.279999999999998 }, "origin": "top" }, @@ -10104,7 +10104,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -10123,13 +10123,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 20.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -10149,13 +10149,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 20.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -10180,7 +10180,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -11.280000000000001 + "z": -11.279999999999998 }, "origin": "top" }, @@ -10199,13 +10199,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 40.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -11.280000000000001 + "z": -11.279999999999998 }, "origin": "top" }, @@ -10225,12 +10225,12 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": 2.0 + "z": 2.000000000000007 }, "origin": "top" }, @@ -10254,7 +10254,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -10288,7 +10288,7 @@ "position": { "x": 32.38, "y": 74.24, - "z": 34.650000000000006 + "z": 34.65 } }, "status": "succeeded" @@ -10302,7 +10302,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -10492,7 +10492,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 10.0, "wellLocation": { "offset": { @@ -10518,7 +10518,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 10.0, "wellLocation": { "offset": { @@ -10534,7 +10534,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 10.0 }, @@ -10559,7 +10559,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -10568,7 +10568,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -10584,7 +10584,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -10594,7 +10594,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -10610,7 +10610,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -10620,7 +10620,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -10636,7 +10636,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -10646,7 +10646,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -10662,7 +10662,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -10672,7 +10672,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -10688,7 +10688,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -10698,7 +10698,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -10714,7 +10714,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -10724,7 +10724,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -10740,7 +10740,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -10750,7 +10750,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -10766,7 +10766,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -10776,7 +10776,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -10792,7 +10792,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -10802,7 +10802,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -10818,7 +10818,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -10828,7 +10828,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -10844,7 +10844,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -10854,7 +10854,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -10870,7 +10870,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -10880,7 +10880,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -10896,7 +10896,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -10906,7 +10906,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -10922,7 +10922,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -10932,7 +10932,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -10948,7 +10948,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -10958,7 +10958,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -10974,7 +10974,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -10984,7 +10984,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11000,7 +11000,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11010,7 +11010,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11026,7 +11026,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11036,7 +11036,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11052,7 +11052,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11062,7 +11062,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11078,7 +11078,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11138,7 +11138,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 10.0, "wellLocation": { "offset": { @@ -11164,7 +11164,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 10.0, "wellLocation": { "offset": { @@ -11180,7 +11180,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 10.0 }, @@ -11205,7 +11205,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -11214,7 +11214,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11230,7 +11230,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11240,7 +11240,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11256,7 +11256,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11266,7 +11266,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11282,7 +11282,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11292,7 +11292,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11308,7 +11308,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11318,7 +11318,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11334,7 +11334,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11344,7 +11344,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11360,7 +11360,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11370,7 +11370,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11386,7 +11386,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11396,7 +11396,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11412,7 +11412,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11422,7 +11422,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11438,7 +11438,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11448,7 +11448,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11464,7 +11464,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11474,7 +11474,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11490,7 +11490,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11500,7 +11500,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11516,7 +11516,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11526,7 +11526,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11542,7 +11542,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11552,7 +11552,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11568,7 +11568,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11578,7 +11578,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11594,7 +11594,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11604,7 +11604,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11620,7 +11620,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11630,7 +11630,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11646,7 +11646,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11656,7 +11656,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11672,7 +11672,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11682,7 +11682,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11698,7 +11698,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11708,7 +11708,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11724,7 +11724,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11784,7 +11784,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 10.0, "wellLocation": { "offset": { @@ -11810,7 +11810,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 10.0, "wellLocation": { "offset": { @@ -11826,7 +11826,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 10.0 }, @@ -11851,7 +11851,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 } }, "status": "succeeded" @@ -11860,7 +11860,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11876,7 +11876,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11886,7 +11886,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11902,7 +11902,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11912,7 +11912,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11928,7 +11928,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11938,7 +11938,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11954,7 +11954,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11964,7 +11964,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -11980,7 +11980,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -11990,7 +11990,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -12006,7 +12006,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -12016,7 +12016,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -12032,7 +12032,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -12042,7 +12042,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -12058,7 +12058,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -12068,7 +12068,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -12084,7 +12084,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -12094,7 +12094,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -12110,7 +12110,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -12120,7 +12120,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -12136,7 +12136,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -12146,7 +12146,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -12162,7 +12162,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -12172,7 +12172,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -12188,7 +12188,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -12198,7 +12198,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -12214,7 +12214,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -12224,7 +12224,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -12240,7 +12240,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -12250,7 +12250,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -12266,7 +12266,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -12276,7 +12276,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -12292,7 +12292,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -12302,7 +12302,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -12318,7 +12318,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -12328,7 +12328,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 20.0, "wellLocation": { "offset": { @@ -12344,7 +12344,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -12354,7 +12354,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 20.0, "wellLocation": { "offset": { @@ -12370,7 +12370,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 1.079999999999993 + "z": 1.08 }, "volume": 20.0 }, @@ -12571,7 +12571,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -12630,7 +12630,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -12680,7 +12680,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -12715,7 +12715,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -12739,7 +12739,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -12839,7 +12839,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -12898,7 +12898,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -12948,7 +12948,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -12983,7 +12983,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -13007,7 +13007,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -13107,7 +13107,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -13166,7 +13166,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -13216,7 +13216,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -13251,7 +13251,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -13275,7 +13275,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -13397,7 +13397,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -13428,7 +13428,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -13447,13 +13447,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -13473,13 +13473,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -13499,13 +13499,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -13525,13 +13525,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -13551,13 +13551,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -13592,7 +13592,7 @@ "position": { "x": 14.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 } }, "status": "succeeded" @@ -13610,7 +13610,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -13625,7 +13625,7 @@ "position": { "x": 14.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 } }, "status": "succeeded" @@ -13634,7 +13634,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -13650,7 +13650,7 @@ "position": { "x": 14.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 }, "volume": 20.0 }, @@ -13710,7 +13710,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -13741,7 +13741,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -13760,13 +13760,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -13786,13 +13786,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -13812,13 +13812,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -13838,13 +13838,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -13864,13 +13864,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -13905,7 +13905,7 @@ "position": { "x": 23.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 } }, "status": "succeeded" @@ -13923,7 +13923,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -13938,7 +13938,7 @@ "position": { "x": 23.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 } }, "status": "succeeded" @@ -13947,7 +13947,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -13963,7 +13963,7 @@ "position": { "x": 23.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 }, "volume": 20.0 }, @@ -14023,7 +14023,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -14054,7 +14054,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -14073,13 +14073,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -14099,13 +14099,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -14125,13 +14125,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -14151,13 +14151,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -14177,13 +14177,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -14218,7 +14218,7 @@ "position": { "x": 32.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 } }, "status": "succeeded" @@ -14236,7 +14236,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -14251,7 +14251,7 @@ "position": { "x": 32.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 } }, "status": "succeeded" @@ -14260,7 +14260,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -14276,7 +14276,7 @@ "position": { "x": 32.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 }, "volume": 20.0 }, @@ -14458,7 +14458,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -14517,7 +14517,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -14543,7 +14543,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -14602,7 +14602,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -14626,7 +14626,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -14726,7 +14726,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -14785,7 +14785,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -14811,7 +14811,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -14870,7 +14870,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -14894,7 +14894,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -14994,7 +14994,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -15053,7 +15053,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -15079,7 +15079,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -15138,7 +15138,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -15162,7 +15162,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -15284,7 +15284,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -15315,7 +15315,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -15334,13 +15334,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -15360,13 +15360,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -15386,13 +15386,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -15412,13 +15412,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -15438,13 +15438,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -15479,7 +15479,7 @@ "position": { "x": 14.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 } }, "status": "succeeded" @@ -15497,7 +15497,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -15512,7 +15512,7 @@ "position": { "x": 14.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 } }, "status": "succeeded" @@ -15521,7 +15521,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -15537,7 +15537,7 @@ "position": { "x": 14.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 }, "volume": 20.0 }, @@ -15597,7 +15597,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -15628,7 +15628,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -15647,13 +15647,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -15673,13 +15673,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -15699,13 +15699,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -15725,13 +15725,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -15751,13 +15751,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -15792,7 +15792,7 @@ "position": { "x": 23.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 } }, "status": "succeeded" @@ -15810,7 +15810,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -15825,7 +15825,7 @@ "position": { "x": 23.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 } }, "status": "succeeded" @@ -15834,7 +15834,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -15850,7 +15850,7 @@ "position": { "x": 23.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 }, "volume": 20.0 }, @@ -15910,7 +15910,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -15941,7 +15941,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -15960,13 +15960,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -15986,13 +15986,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -16012,13 +16012,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -16038,13 +16038,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -16064,13 +16064,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -16105,7 +16105,7 @@ "position": { "x": 32.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 } }, "status": "succeeded" @@ -16123,7 +16123,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -16138,7 +16138,7 @@ "position": { "x": 32.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 } }, "status": "succeeded" @@ -16147,7 +16147,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -16163,7 +16163,7 @@ "position": { "x": 32.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 }, "volume": 20.0 }, @@ -16345,7 +16345,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -16404,7 +16404,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -16430,7 +16430,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -16489,7 +16489,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -16513,7 +16513,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -16613,7 +16613,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -16672,7 +16672,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -16698,7 +16698,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -16757,7 +16757,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -16781,7 +16781,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -16881,7 +16881,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -16940,7 +16940,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -16966,7 +16966,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -17025,7 +17025,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -17049,7 +17049,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -17171,7 +17171,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -17202,7 +17202,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -17221,13 +17221,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -17247,13 +17247,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -17273,13 +17273,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -17299,13 +17299,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -17325,13 +17325,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -17366,7 +17366,7 @@ "position": { "x": 14.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 } }, "status": "succeeded" @@ -17384,7 +17384,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -17399,7 +17399,7 @@ "position": { "x": 14.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 } }, "status": "succeeded" @@ -17408,7 +17408,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -17424,7 +17424,7 @@ "position": { "x": 14.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 }, "volume": 20.0 }, @@ -17484,7 +17484,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -17515,7 +17515,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -17534,13 +17534,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -17560,13 +17560,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -17586,13 +17586,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -17612,13 +17612,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -17638,13 +17638,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -17679,7 +17679,7 @@ "position": { "x": 23.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 } }, "status": "succeeded" @@ -17697,7 +17697,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -17712,7 +17712,7 @@ "position": { "x": 23.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 } }, "status": "succeeded" @@ -17721,7 +17721,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -17737,7 +17737,7 @@ "position": { "x": 23.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 }, "volume": 20.0 }, @@ -17797,7 +17797,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -17828,7 +17828,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -17847,13 +17847,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -17873,13 +17873,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -17899,13 +17899,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -17925,13 +17925,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -17951,13 +17951,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 90.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -17992,7 +17992,7 @@ "position": { "x": 32.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 } }, "status": "succeeded" @@ -18010,7 +18010,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -18025,7 +18025,7 @@ "position": { "x": 32.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 } }, "status": "succeeded" @@ -18034,7 +18034,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -18050,7 +18050,7 @@ "position": { "x": 32.38, "y": 74.24, - "z": 35.650000000000006 + "z": 35.65 }, "volume": 20.0 }, @@ -18232,7 +18232,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -18291,7 +18291,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -18317,7 +18317,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18376,7 +18376,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -18400,7 +18400,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -18500,7 +18500,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -18559,7 +18559,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -18585,7 +18585,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18644,7 +18644,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -18668,7 +18668,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -18768,7 +18768,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -18827,7 +18827,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -18853,7 +18853,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -18912,7 +18912,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -18936,7 +18936,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 20.0, "wellLocation": { "offset": { @@ -19055,7 +19055,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 20.0, "wellLocation": { "offset": { @@ -19155,7 +19155,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 20.0, "wellLocation": { "offset": { @@ -19255,7 +19255,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 20.0, "wellLocation": { "offset": { @@ -19386,7 +19386,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -19417,7 +19417,7 @@ "offset": { "x": 1.040000000000001, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -19436,13 +19436,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 1.040000000000001, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -19467,7 +19467,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -19486,13 +19486,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -19517,7 +19517,7 @@ "offset": { "x": 0.0, "y": 1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -19536,13 +19536,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 0.0, "y": 1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -19567,7 +19567,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -19586,13 +19586,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -19617,7 +19617,7 @@ "offset": { "x": -1.040000000000001, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -19636,13 +19636,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": -1.040000000000001, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -19667,7 +19667,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -19686,13 +19686,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -19717,7 +19717,7 @@ "offset": { "x": 0.0, "y": -1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -19736,13 +19736,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 0.0, "y": -1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -19767,7 +19767,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -19786,13 +19786,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -19812,13 +19812,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -19838,12 +19838,12 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -7.390000000000001 + "z": -7.389999999999997 }, "origin": "top" }, @@ -19867,7 +19867,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -19901,7 +19901,7 @@ "position": { "x": 14.38, "y": 74.24, - "z": 34.650000000000006 + "z": 34.65 } }, "status": "succeeded" @@ -19915,7 +19915,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -19984,7 +19984,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -20015,7 +20015,7 @@ "offset": { "x": 1.0399999999999991, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -20034,13 +20034,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 1.0399999999999991, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -20065,7 +20065,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -20084,13 +20084,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -20115,7 +20115,7 @@ "offset": { "x": 0.0, "y": 1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -20134,13 +20134,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 0.0, "y": 1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -20165,7 +20165,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -20184,13 +20184,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -20215,7 +20215,7 @@ "offset": { "x": -1.0399999999999991, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -20234,13 +20234,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": -1.0399999999999991, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -20265,7 +20265,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -20284,13 +20284,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -20315,7 +20315,7 @@ "offset": { "x": 0.0, "y": -1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -20334,13 +20334,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 0.0, "y": -1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -20365,7 +20365,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -20384,13 +20384,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -20410,13 +20410,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -20436,12 +20436,12 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -7.390000000000001 + "z": -7.389999999999997 }, "origin": "top" }, @@ -20465,7 +20465,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -20499,7 +20499,7 @@ "position": { "x": 23.38, "y": 74.24, - "z": 34.650000000000006 + "z": 34.65 } }, "status": "succeeded" @@ -20513,7 +20513,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -20582,7 +20582,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -20613,7 +20613,7 @@ "offset": { "x": 1.0399999999999991, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -20632,13 +20632,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 1.0399999999999991, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -20663,7 +20663,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -20682,13 +20682,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -20713,7 +20713,7 @@ "offset": { "x": 0.0, "y": 1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -20732,13 +20732,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 0.0, "y": 1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -20763,7 +20763,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -20782,13 +20782,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -20813,7 +20813,7 @@ "offset": { "x": -1.0399999999999991, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -20832,13 +20832,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": -1.0399999999999991, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -20863,7 +20863,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -20882,13 +20882,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -20913,7 +20913,7 @@ "offset": { "x": 0.0, "y": -1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -20932,13 +20932,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 0.0, "y": -1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -20963,7 +20963,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -20982,13 +20982,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -21008,13 +21008,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 35.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -21034,12 +21034,12 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -7.390000000000001 + "z": -7.389999999999997 }, "origin": "top" }, @@ -21063,7 +21063,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -21097,7 +21097,7 @@ "position": { "x": 32.38, "y": 74.24, - "z": 34.650000000000006 + "z": 34.65 } }, "status": "succeeded" @@ -21111,7 +21111,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -21269,7 +21269,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 10.0, "wellLocation": { "offset": { @@ -21295,7 +21295,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 10.0, "wellLocation": { "offset": { @@ -21311,7 +21311,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 10.0 }, @@ -21321,7 +21321,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 10.0, "wellLocation": { "offset": { @@ -21337,7 +21337,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 10.0 }, @@ -21347,7 +21347,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 10.0, "wellLocation": { "offset": { @@ -21363,7 +21363,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 10.0 }, @@ -21373,7 +21373,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 10.0, "wellLocation": { "offset": { @@ -21389,7 +21389,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 10.0 }, @@ -21399,7 +21399,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 10.0, "wellLocation": { "offset": { @@ -21415,7 +21415,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 10.0 }, @@ -21425,7 +21425,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 10.0, "wellLocation": { "offset": { @@ -21441,7 +21441,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 10.0 }, @@ -21451,7 +21451,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 10.0, "wellLocation": { "offset": { @@ -21467,7 +21467,7 @@ "position": { "x": -5.624999999999998, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 10.0 }, @@ -21527,7 +21527,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 10.0, "wellLocation": { "offset": { @@ -21553,7 +21553,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 10.0, "wellLocation": { "offset": { @@ -21569,7 +21569,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 10.0 }, @@ -21579,7 +21579,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 10.0, "wellLocation": { "offset": { @@ -21595,7 +21595,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 10.0 }, @@ -21605,7 +21605,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 10.0, "wellLocation": { "offset": { @@ -21621,7 +21621,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 10.0 }, @@ -21631,7 +21631,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 10.0, "wellLocation": { "offset": { @@ -21647,7 +21647,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 10.0 }, @@ -21657,7 +21657,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 10.0, "wellLocation": { "offset": { @@ -21673,7 +21673,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 10.0 }, @@ -21683,7 +21683,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 10.0, "wellLocation": { "offset": { @@ -21699,7 +21699,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 10.0 }, @@ -21709,7 +21709,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 10.0, "wellLocation": { "offset": { @@ -21725,7 +21725,7 @@ "position": { "x": 3.375, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 10.0 }, @@ -21785,7 +21785,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 2.0, + "flowRate": 8.75, "volume": 10.0, "wellLocation": { "offset": { @@ -21811,7 +21811,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 10.0, "wellLocation": { "offset": { @@ -21827,7 +21827,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 10.0 }, @@ -21837,7 +21837,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 10.0, "wellLocation": { "offset": { @@ -21853,7 +21853,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 10.0 }, @@ -21863,7 +21863,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 10.0, "wellLocation": { "offset": { @@ -21879,7 +21879,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 10.0 }, @@ -21889,7 +21889,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 10.0, "wellLocation": { "offset": { @@ -21905,7 +21905,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 10.0 }, @@ -21915,7 +21915,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 10.0, "wellLocation": { "offset": { @@ -21931,7 +21931,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 10.0 }, @@ -21941,7 +21941,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 35.0, "volume": 10.0, "wellLocation": { "offset": { @@ -21957,7 +21957,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 10.0 }, @@ -21967,7 +21967,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 8.0, + "flowRate": 57.0, "volume": 10.0, "wellLocation": { "offset": { @@ -21983,7 +21983,7 @@ "position": { "x": 12.375000000000004, "y": 356.2, - "z": 2.079999999999993 + "z": 2.08 }, "volume": 10.0 }, @@ -22275,7 +22275,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -22301,13 +22301,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -22327,13 +22327,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -14.780000000000001 + "z": -14.779999999999998 }, "origin": "top" }, @@ -22353,13 +22353,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -22429,7 +22429,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -22455,13 +22455,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -22481,13 +22481,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -14.780000000000001 + "z": -14.779999999999998 }, "origin": "top" }, @@ -22507,13 +22507,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -22583,7 +22583,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { @@ -22609,13 +22609,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 40.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -22635,13 +22635,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -14.780000000000001 + "z": -14.779999999999998 }, "origin": "top" }, @@ -22661,13 +22661,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 45.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -22747,7 +22747,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 55.0, "wellLocation": { "offset": { @@ -22773,7 +22773,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 55.0, "wellLocation": { "offset": { @@ -22799,7 +22799,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 55.0, "wellLocation": { "offset": { @@ -22825,7 +22825,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 55.0, "wellLocation": { "offset": { @@ -22851,7 +22851,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 55.0, "wellLocation": { "offset": { @@ -22877,7 +22877,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 55.0, "wellLocation": { "offset": { @@ -22903,7 +22903,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 45.0, "wellLocation": { "offset": { @@ -22929,13 +22929,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 45.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -22960,7 +22960,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -9.780000000000001 + "z": -9.779999999999998 }, "origin": "top" }, @@ -22979,13 +22979,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -9.780000000000001 + "z": -9.779999999999998 }, "origin": "top" }, @@ -23010,7 +23010,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -23029,13 +23029,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -23055,13 +23055,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -23086,7 +23086,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -9.780000000000001 + "z": -9.779999999999998 }, "origin": "top" }, @@ -23105,13 +23105,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -9.780000000000001 + "z": -9.779999999999998 }, "origin": "top" }, @@ -23131,13 +23131,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -9.780000000000001 + "z": -9.779999999999998 }, "origin": "top" }, @@ -23162,7 +23162,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -23181,13 +23181,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -23207,13 +23207,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -23238,7 +23238,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -9.780000000000001 + "z": -9.779999999999998 }, "origin": "top" }, @@ -23257,13 +23257,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -9.780000000000001 + "z": -9.779999999999998 }, "origin": "top" }, @@ -23283,12 +23283,12 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": 2.0 + "z": 2.000000000000007 }, "origin": "top" }, @@ -23312,7 +23312,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -23346,7 +23346,7 @@ "position": { "x": 50.38, "y": 74.24, - "z": 34.650000000000006 + "z": 34.65 } }, "status": "succeeded" @@ -23360,7 +23360,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -23429,7 +23429,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 55.0, "wellLocation": { "offset": { @@ -23455,7 +23455,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 55.0, "wellLocation": { "offset": { @@ -23481,7 +23481,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 55.0, "wellLocation": { "offset": { @@ -23507,7 +23507,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 55.0, "wellLocation": { "offset": { @@ -23533,7 +23533,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 55.0, "wellLocation": { "offset": { @@ -23559,7 +23559,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 55.0, "wellLocation": { "offset": { @@ -23585,7 +23585,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 45.0, "wellLocation": { "offset": { @@ -23611,13 +23611,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 45.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -23642,7 +23642,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -9.780000000000001 + "z": -9.779999999999998 }, "origin": "top" }, @@ -23661,13 +23661,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -9.780000000000001 + "z": -9.779999999999998 }, "origin": "top" }, @@ -23692,7 +23692,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -23711,13 +23711,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -23737,13 +23737,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -23768,7 +23768,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -9.780000000000001 + "z": -9.779999999999998 }, "origin": "top" }, @@ -23787,13 +23787,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -9.780000000000001 + "z": -9.779999999999998 }, "origin": "top" }, @@ -23813,13 +23813,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -9.780000000000001 + "z": -9.779999999999998 }, "origin": "top" }, @@ -23844,7 +23844,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -23863,13 +23863,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -23889,13 +23889,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -23920,7 +23920,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -9.780000000000001 + "z": -9.779999999999998 }, "origin": "top" }, @@ -23939,13 +23939,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -9.780000000000001 + "z": -9.779999999999998 }, "origin": "top" }, @@ -23965,12 +23965,12 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": 2.0 + "z": 2.000000000000007 }, "origin": "top" }, @@ -23994,7 +23994,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -24028,7 +24028,7 @@ "position": { "x": 59.38, "y": 74.24, - "z": 34.650000000000006 + "z": 34.65 } }, "status": "succeeded" @@ -24042,7 +24042,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -24111,7 +24111,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 55.0, "wellLocation": { "offset": { @@ -24137,7 +24137,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 55.0, "wellLocation": { "offset": { @@ -24163,7 +24163,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 55.0, "wellLocation": { "offset": { @@ -24189,7 +24189,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 55.0, "wellLocation": { "offset": { @@ -24215,7 +24215,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 55.0, "wellLocation": { "offset": { @@ -24241,7 +24241,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 55.0, "wellLocation": { "offset": { @@ -24267,7 +24267,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 45.0, "wellLocation": { "offset": { @@ -24293,13 +24293,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 45.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -24324,7 +24324,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -9.780000000000001 + "z": -9.779999999999998 }, "origin": "top" }, @@ -24343,13 +24343,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -9.780000000000001 + "z": -9.779999999999998 }, "origin": "top" }, @@ -24374,7 +24374,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -24393,13 +24393,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -24419,13 +24419,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -24450,7 +24450,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -9.780000000000001 + "z": -9.779999999999998 }, "origin": "top" }, @@ -24469,13 +24469,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -9.780000000000001 + "z": -9.779999999999998 }, "origin": "top" }, @@ -24495,13 +24495,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -9.780000000000001 + "z": -9.779999999999998 }, "origin": "top" }, @@ -24526,7 +24526,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -24545,13 +24545,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -24571,13 +24571,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 60.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -24602,7 +24602,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -9.780000000000001 + "z": -9.779999999999998 }, "origin": "top" }, @@ -24621,13 +24621,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 358.0, "volume": 30.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -9.780000000000001 + "z": -9.779999999999998 }, "origin": "top" }, @@ -24647,12 +24647,12 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": 2.0 + "z": 2.000000000000007 }, "origin": "top" }, @@ -24676,7 +24676,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -24710,7 +24710,7 @@ "position": { "x": 68.38, "y": 74.24, - "z": 34.650000000000006 + "z": 34.65 } }, "status": "succeeded" @@ -24724,7 +24724,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -24899,7 +24899,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -24958,7 +24958,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -25008,7 +25008,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -25043,7 +25043,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -25189,7 +25189,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -25248,7 +25248,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -25298,7 +25298,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -25333,7 +25333,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -25479,7 +25479,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -25538,7 +25538,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -25588,7 +25588,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -25623,7 +25623,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -25755,7 +25755,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -25877,7 +25877,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -25912,7 +25912,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -26008,7 +26008,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -26130,7 +26130,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -26165,7 +26165,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -26261,7 +26261,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -26383,7 +26383,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -26418,7 +26418,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -26607,7 +26607,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -26666,7 +26666,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -26716,7 +26716,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -26751,7 +26751,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -26897,7 +26897,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -26956,7 +26956,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -27006,7 +27006,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -27041,7 +27041,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -27187,7 +27187,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -27246,7 +27246,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -27296,7 +27296,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -27331,7 +27331,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -27463,7 +27463,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -27585,7 +27585,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -27620,7 +27620,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -27716,7 +27716,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -27838,7 +27838,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -27873,7 +27873,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -27969,7 +27969,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -28091,7 +28091,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 150.0, "wellLocation": { "offset": { @@ -28126,7 +28126,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -28315,7 +28315,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -28374,7 +28374,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -28424,7 +28424,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -28459,7 +28459,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -28605,7 +28605,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -28664,7 +28664,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -28714,7 +28714,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -28749,7 +28749,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -28895,7 +28895,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -28954,7 +28954,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 100.0, "wellLocation": { "offset": { @@ -29004,7 +29004,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 200.0, "wellLocation": { "offset": { @@ -29039,7 +29039,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -29204,7 +29204,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -29230,7 +29230,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.0, "wellLocation": { "offset": { @@ -29265,7 +29265,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -29411,7 +29411,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -29437,7 +29437,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.0, "wellLocation": { "offset": { @@ -29472,7 +29472,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -29618,7 +29618,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 50.0, "wellLocation": { "offset": { @@ -29644,7 +29644,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 50.0, "wellLocation": { "offset": { @@ -29679,7 +29679,7 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, @@ -29856,7 +29856,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -29887,7 +29887,7 @@ "offset": { "x": 1.0399999999999991, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -29906,13 +29906,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 1.0399999999999991, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -29937,7 +29937,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -29956,13 +29956,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -29987,7 +29987,7 @@ "offset": { "x": 0.0, "y": 1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -30006,13 +30006,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 0.0, "y": 1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -30037,7 +30037,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -30056,13 +30056,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -30087,7 +30087,7 @@ "offset": { "x": -1.0399999999999991, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -30106,13 +30106,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": -1.0399999999999991, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -30137,7 +30137,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -30156,13 +30156,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -30187,7 +30187,7 @@ "offset": { "x": 0.0, "y": -1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -30206,13 +30206,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 0.0, "y": -1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -30237,7 +30237,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -30256,13 +30256,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -30282,13 +30282,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -30308,12 +30308,12 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -7.390000000000001 + "z": -7.389999999999997 }, "origin": "top" }, @@ -30337,7 +30337,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -30371,7 +30371,7 @@ "position": { "x": 50.38, "y": 74.24, - "z": 34.650000000000006 + "z": 34.65 } }, "status": "succeeded" @@ -30385,7 +30385,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -30454,7 +30454,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -30485,7 +30485,7 @@ "offset": { "x": 1.0399999999999991, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -30504,13 +30504,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 1.0399999999999991, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -30535,7 +30535,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -30554,13 +30554,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -30585,7 +30585,7 @@ "offset": { "x": 0.0, "y": 1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -30604,13 +30604,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 0.0, "y": 1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -30635,7 +30635,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -30654,13 +30654,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -30685,7 +30685,7 @@ "offset": { "x": -1.0399999999999991, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -30704,13 +30704,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": -1.0399999999999991, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -30735,7 +30735,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -30754,13 +30754,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -30785,7 +30785,7 @@ "offset": { "x": 0.0, "y": -1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -30804,13 +30804,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 0.0, "y": -1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -30835,7 +30835,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -30854,13 +30854,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -30880,13 +30880,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -30906,12 +30906,12 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -7.390000000000001 + "z": -7.389999999999997 }, "origin": "top" }, @@ -30935,7 +30935,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -30969,7 +30969,7 @@ "position": { "x": 59.38, "y": 74.24, - "z": 34.650000000000006 + "z": 34.65 } }, "status": "succeeded" @@ -30983,7 +30983,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -31052,7 +31052,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { @@ -31083,7 +31083,7 @@ "offset": { "x": 1.0400000000000063, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -31102,13 +31102,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 1.0400000000000063, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -31133,7 +31133,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -31152,13 +31152,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -31183,7 +31183,7 @@ "offset": { "x": 0.0, "y": 1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -31202,13 +31202,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 0.0, "y": 1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -31233,7 +31233,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -31252,13 +31252,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -31283,7 +31283,7 @@ "offset": { "x": -1.0400000000000063, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -31302,13 +31302,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": -1.0400000000000063, "y": 0.0, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -31333,7 +31333,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -31352,13 +31352,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -31383,7 +31383,7 @@ "offset": { "x": 0.0, "y": -1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -31402,13 +31402,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 0.0, "y": -1.0400000000000063, - "z": -11.39 + "z": -11.389999999999997 }, "origin": "top" }, @@ -31433,7 +31433,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -31452,13 +31452,13 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -31478,13 +31478,13 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 32.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -13.780000000000001 + "z": -13.779999999999998 }, "origin": "top" }, @@ -31504,12 +31504,12 @@ "commandType": "blowout", "notes": [], "params": { - "flowRate": 80.0, + "flowRate": 716.0, "wellLocation": { "offset": { "x": 0.0, "y": 0.0, - "z": -7.390000000000001 + "z": -7.389999999999997 }, "origin": "top" }, @@ -31533,7 +31533,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -31567,7 +31567,7 @@ "position": { "x": 68.38, "y": 74.24, - "z": 34.650000000000006 + "z": 34.65 } }, "status": "succeeded" @@ -31581,7 +31581,7 @@ "offset": { "x": 0.0, "y": 0.0, - "z": 5.0 + "z": 5.000000000000007 }, "origin": "top" }, @@ -31756,7 +31756,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 31.0, "wellLocation": { "offset": { @@ -31782,7 +31782,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -31882,7 +31882,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 31.0, "wellLocation": { "offset": { @@ -31908,7 +31908,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -32008,7 +32008,7 @@ "commandType": "aspirate", "notes": [], "params": { - "flowRate": 40.0, + "flowRate": 179.0, "volume": 31.0, "wellLocation": { "offset": { @@ -32034,7 +32034,7 @@ "commandType": "dispense", "notes": [], "params": { - "flowRate": 160.0, + "flowRate": 716.0, "volume": 31.0, "wellLocation": { "offset": { @@ -32091,7 +32091,7 @@ "errors": [], "files": [ { - "name": "Flex_P1000MLeft_P50MRight_HS_TM_MM_TC_2_15_ABR4_Illumina_DNA_Prep_24x.py", + "name": "Flex_S_v2_15_P1000M_P50M_GRIP_HS_MB_TC_TM_IlluminaDNAPrep24x.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[ed1e64c539][Flex_X_v2_16_NO_PIPETTES_TM_ModuleInCol2].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[ed1e64c539][Flex_X_v2_16_NO_PIPETTES_TM_ModuleInCol2].json new file mode 100644 index 00000000000..507c5d11bee --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[ed1e64c539][Flex_X_v2_16_NO_PIPETTES_TM_ModuleInCol2].json @@ -0,0 +1,105 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + }, + { + "commandType": "loadModule", + "error": { + "detail": "ValueError: A temperatureModuleType cannot be loaded into slot C2", + "errorCode": "4000", + "errorInfo": { + "args": "('A temperatureModuleType cannot be loaded into slot C2',)", + "class": "ValueError", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/execution/command_executor.py\", line 150, in execute\n result: CommandResult = await command_impl.execute(running_command.params) # type: ignore[arg-type]\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/commands/load_module.py\", line 116, in execute\n self._ensure_module_location(params.location.slotName, module_type)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/commands/load_module.py\", line 176, in _ensure_module_location\n raise ValueError(\n" + }, + "errorType": "PythonException", + "wrappedErrors": [] + }, + "notes": [], + "params": { + "location": { + "slotName": "C2" + }, + "model": "temperatureModuleV2" + }, + "status": "failed" + } + ], + "config": { + "apiVersion": [ + 2, + 16 + ], + "protocolType": "python" + }, + "errors": [ + { + "detail": "ProtocolCommandFailedError [line 15]: Error 4000 GENERAL_ERROR (ProtocolCommandFailedError): PythonException: ValueError: A temperatureModuleType cannot be loaded into slot C2", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ExceptionInProtocolError", + "wrappedErrors": [ + { + "detail": "PythonException: ValueError: A temperatureModuleType cannot be loaded into slot C2", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ProtocolCommandFailedError", + "wrappedErrors": [ + { + "detail": "ValueError: A temperatureModuleType cannot be loaded into slot C2", + "errorCode": "4000", + "errorInfo": { + "args": "('A temperatureModuleType cannot be loaded into slot C2',)", + "class": "ValueError", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/execution/command_executor.py\", line 150, in execute\n result: CommandResult = await command_impl.execute(running_command.params) # type: ignore[arg-type]\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/commands/load_module.py\", line 116, in execute\n self._ensure_module_location(params.location.slotName, module_type)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_engine/commands/load_module.py\", line 176, in _ensure_module_location\n raise ValueError(\n" + }, + "errorType": "PythonException", + "wrappedErrors": [] + } + ] + } + ] + } + ], + "files": [ + { + "name": "Flex_X_v2_16_NO_PIPETTES_TM_ModuleInCol2.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "author": "Derek Maggio ", + "protocolName": "QA Protocol - Analysis Error - Module in Column 2" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-3 Standard", + "runTimeParameters": [] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[01a37ee87b][Flex_P1000_96_2_16_AnalysisError_DropTipsWithNoTrash].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f0efddcd7d][Flex_X_v2_16_P1000_96_DropTipsWithNoTrash].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[01a37ee87b][Flex_P1000_96_2_16_AnalysisError_DropTipsWithNoTrash].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f0efddcd7d][Flex_X_v2_16_P1000_96_DropTipsWithNoTrash].json index 9139bc0c57d..e4b54680e8a 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[01a37ee87b][Flex_P1000_96_2_16_AnalysisError_DropTipsWithNoTrash].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f0efddcd7d][Flex_X_v2_16_P1000_96_DropTipsWithNoTrash].json @@ -1370,7 +1370,7 @@ ], "files": [ { - "name": "Flex_P1000_96_2_16_AnalysisError_DropTipsWithNoTrash.py", + "name": "Flex_X_v2_16_P1000_96_DropTipsWithNoTrash.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[adca5df246][Flex_P1000_96_HS_TM_TC_MM_2_15_ABR5_6_Illumina_DNA_Prep_96x_Head_PART_III].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f24bb0b4d9][Flex_S_v2_15_P1000_96_GRIP_HS_MB_TC_TM_IlluminaDNAPrep96PART3].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[adca5df246][Flex_P1000_96_HS_TM_TC_MM_2_15_ABR5_6_Illumina_DNA_Prep_96x_Head_PART_III].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f24bb0b4d9][Flex_S_v2_15_P1000_96_GRIP_HS_MB_TC_TM_IlluminaDNAPrep96PART3].json index d664bc8fc3d..f71b0969ee6 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[adca5df246][Flex_P1000_96_HS_TM_TC_MM_2_15_ABR5_6_Illumina_DNA_Prep_96x_Head_PART_III].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f24bb0b4d9][Flex_S_v2_15_P1000_96_GRIP_HS_MB_TC_TM_IlluminaDNAPrep96PART3].json @@ -5774,7 +5774,7 @@ ], "files": [ { - "name": "Flex_P1000_96_HS_TM_TC_MM_2_15_ABR5_6_Illumina_DNA_Prep_96x_Head_PART_III.py", + "name": "Flex_S_v2_15_P1000_96_GRIP_HS_MB_TC_TM_IlluminaDNAPrep96PART3.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[49c3817e54][OT2_P300M_P300S_HS_6_1_HS_NormalUseWithTransfer].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f301704f56][OT2_S_v6_P300M_P300S_HS_HS_NormalUseWithTransfer].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[49c3817e54][OT2_P300M_P300S_HS_6_1_HS_NormalUseWithTransfer].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f301704f56][OT2_S_v6_P300M_P300S_HS_HS_NormalUseWithTransfer].json index 213e9a6d6ea..a116d308217 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[49c3817e54][OT2_P300M_P300S_HS_6_1_HS_NormalUseWithTransfer].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f301704f56][OT2_S_v6_P300M_P300S_HS_HS_NormalUseWithTransfer].json @@ -6382,7 +6382,7 @@ "errors": [], "files": [ { - "name": "OT2_P300M_P300S_HS_6_1_HS_NormalUseWithTransfer.json", + "name": "OT2_S_v6_P300M_P300S_HS_HS_NormalUseWithTransfer.json", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f3ec1e065e][OT2_P300M_P20S_MM_TM_TC1_5_2_6_PD40].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f345e8e33a][OT2_S_v4_P300M_P20S_MM_TM_TC1_PD40].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f3ec1e065e][OT2_P300M_P20S_MM_TM_TC1_5_2_6_PD40].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f345e8e33a][OT2_S_v4_P300M_P20S_MM_TM_TC1_PD40].json index e9c1b191c53..df6100f8a51 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f3ec1e065e][OT2_P300M_P20S_MM_TM_TC1_5_2_6_PD40].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f345e8e33a][OT2_S_v4_P300M_P20S_MM_TM_TC1_PD40].json @@ -9606,7 +9606,7 @@ "errors": [], "files": [ { - "name": "OT2_P300M_P20S_MM_TM_TC1_5_2_6_PD40.json", + "name": "OT2_S_v4_P300M_P20S_MM_TM_TC1_PD40.json", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[9b9f87acb0][OT2_None_None_2_16_verifyDoesNotDeadlock].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f37bb0ec36][OT2_S_v2_16_NO_PIPETTES_verifyDoesNotDeadlock].json similarity index 93% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[9b9f87acb0][OT2_None_None_2_16_verifyDoesNotDeadlock].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f37bb0ec36][OT2_S_v2_16_NO_PIPETTES_verifyDoesNotDeadlock].json index 6e5243e7ff0..73c621e5e54 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[9b9f87acb0][OT2_None_None_2_16_verifyDoesNotDeadlock].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f37bb0ec36][OT2_S_v2_16_NO_PIPETTES_verifyDoesNotDeadlock].json @@ -18,7 +18,7 @@ "errors": [], "files": [ { - "name": "OT2_None_None_2_16_verifyDoesNotDeadlock.py", + "name": "OT2_S_v2_16_NO_PIPETTES_verifyDoesNotDeadlock.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[2a185c4e1c][Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_Smoke].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f51172f73b][Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_Smoke].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[2a185c4e1c][Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_Smoke].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f51172f73b][Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_Smoke].json index c22b8b7efe6..05c042f1933 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[2a185c4e1c][Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_Smoke].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f51172f73b][Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_Smoke].json @@ -8291,7 +8291,7 @@ "notes": [], "params": { "addressableAreaName": "movableTrashB3", - "alternateDropLocation": false, + "alternateDropLocation": true, "forceDirect": false, "ignoreTipConfiguration": true, "offset": { @@ -8302,7 +8302,7 @@ }, "result": { "position": { - "x": 434.25, + "x": 466.25, "y": 257.0, "z": 40.0 } @@ -8399,7 +8399,7 @@ "notes": [], "params": { "addressableAreaName": "movableTrashB3", - "alternateDropLocation": false, + "alternateDropLocation": true, "forceDirect": false, "ignoreTipConfiguration": true, "offset": { @@ -8410,7 +8410,7 @@ }, "result": { "position": { - "x": 434.25, + "x": 402.25, "y": 257.0, "z": 40.0 } @@ -8507,7 +8507,7 @@ "notes": [], "params": { "addressableAreaName": "movableTrashB3", - "alternateDropLocation": false, + "alternateDropLocation": true, "forceDirect": false, "ignoreTipConfiguration": true, "offset": { @@ -8518,7 +8518,7 @@ }, "result": { "position": { - "x": 434.25, + "x": 466.25, "y": 257.0, "z": 40.0 } @@ -8615,7 +8615,7 @@ "notes": [], "params": { "addressableAreaName": "movableTrashB3", - "alternateDropLocation": false, + "alternateDropLocation": true, "forceDirect": false, "ignoreTipConfiguration": true, "offset": { @@ -8626,7 +8626,7 @@ }, "result": { "position": { - "x": 434.25, + "x": 402.25, "y": 257.0, "z": 40.0 } @@ -8723,7 +8723,7 @@ "notes": [], "params": { "addressableAreaName": "movableTrashB3", - "alternateDropLocation": false, + "alternateDropLocation": true, "forceDirect": false, "ignoreTipConfiguration": true, "offset": { @@ -8734,7 +8734,7 @@ }, "result": { "position": { - "x": 434.25, + "x": 466.25, "y": 257.0, "z": 40.0 } @@ -8831,7 +8831,7 @@ "notes": [], "params": { "addressableAreaName": "movableTrashB3", - "alternateDropLocation": false, + "alternateDropLocation": true, "forceDirect": false, "ignoreTipConfiguration": true, "offset": { @@ -8842,7 +8842,7 @@ }, "result": { "position": { - "x": 434.25, + "x": 402.25, "y": 257.0, "z": 40.0 } @@ -8939,7 +8939,7 @@ "notes": [], "params": { "addressableAreaName": "movableTrashB3", - "alternateDropLocation": false, + "alternateDropLocation": true, "forceDirect": false, "ignoreTipConfiguration": true, "offset": { @@ -8950,7 +8950,7 @@ }, "result": { "position": { - "x": 434.25, + "x": 466.25, "y": 257.0, "z": 40.0 } @@ -9047,7 +9047,7 @@ "notes": [], "params": { "addressableAreaName": "movableTrashB3", - "alternateDropLocation": false, + "alternateDropLocation": true, "forceDirect": false, "ignoreTipConfiguration": true, "offset": { @@ -9058,7 +9058,7 @@ }, "result": { "position": { - "x": 434.25, + "x": 402.25, "y": 257.0, "z": 40.0 } @@ -9155,7 +9155,7 @@ "notes": [], "params": { "addressableAreaName": "movableTrashB3", - "alternateDropLocation": false, + "alternateDropLocation": true, "forceDirect": false, "ignoreTipConfiguration": true, "offset": { @@ -9166,7 +9166,7 @@ }, "result": { "position": { - "x": 434.25, + "x": 466.25, "y": 257.0, "z": 40.0 } @@ -9263,7 +9263,7 @@ "notes": [], "params": { "addressableAreaName": "movableTrashB3", - "alternateDropLocation": false, + "alternateDropLocation": true, "forceDirect": false, "ignoreTipConfiguration": true, "offset": { @@ -9274,7 +9274,7 @@ }, "result": { "position": { - "x": 434.25, + "x": 402.25, "y": 257.0, "z": 40.0 } @@ -9371,7 +9371,7 @@ "notes": [], "params": { "addressableAreaName": "movableTrashB3", - "alternateDropLocation": false, + "alternateDropLocation": true, "forceDirect": false, "ignoreTipConfiguration": true, "offset": { @@ -9382,7 +9382,7 @@ }, "result": { "position": { - "x": 434.25, + "x": 466.25, "y": 257.0, "z": 40.0 } @@ -9479,7 +9479,7 @@ "notes": [], "params": { "addressableAreaName": "movableTrashB3", - "alternateDropLocation": false, + "alternateDropLocation": true, "forceDirect": false, "ignoreTipConfiguration": true, "offset": { @@ -9490,7 +9490,7 @@ }, "result": { "position": { - "x": 434.25, + "x": 402.25, "y": 257.0, "z": 40.0 } @@ -12900,7 +12900,7 @@ "errors": [], "files": [ { - "name": "Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_Smoke.py", + "name": "Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_Smoke.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[d8ec3534d4][Flex_P1000_96_TM_2_16_AnalysisError_ModuleAndWasteChuteConflict].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f5f3b9c5bb][Flex_X_v2_16_P1000_96_TM_ModuleAndWasteChuteConflict].json similarity index 95% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[d8ec3534d4][Flex_P1000_96_TM_2_16_AnalysisError_ModuleAndWasteChuteConflict].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f5f3b9c5bb][Flex_X_v2_16_P1000_96_TM_ModuleAndWasteChuteConflict].json index 85e9ca095c0..48fdecffa9e 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[d8ec3534d4][Flex_P1000_96_TM_2_16_AnalysisError_ModuleAndWasteChuteConflict].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f5f3b9c5bb][Flex_X_v2_16_P1000_96_TM_ModuleAndWasteChuteConflict].json @@ -1219,6 +1219,24 @@ } }, "status": "succeeded" + }, + { + "commandType": "loadModule", + "error": { + "detail": "Cannot use Temperature Module in D3, not compatible with one or more of the following fixtures: Waste Chute", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "IncompatibleAddressableAreaError", + "wrappedErrors": [] + }, + "notes": [], + "params": { + "location": { + "slotName": "D3" + }, + "model": "temperatureModuleV2" + }, + "status": "failed" } ], "config": { @@ -1230,24 +1248,32 @@ }, "errors": [ { - "detail": "IncompatibleAddressableAreaError [line 19]: Error 4000 GENERAL_ERROR (IncompatibleAddressableAreaError): Cannot use Slot D3, not compatible with one or more of the following fixtures: Waste Chute", + "detail": "ProtocolCommandFailedError [line 19]: Error 4000 GENERAL_ERROR (ProtocolCommandFailedError): IncompatibleAddressableAreaError: Cannot use Temperature Module in D3, not compatible with one or more of the following fixtures: Waste Chute", "errorCode": "4000", "errorInfo": {}, "errorType": "ExceptionInProtocolError", "wrappedErrors": [ { - "detail": "Cannot use Slot D3, not compatible with one or more of the following fixtures: Waste Chute", + "detail": "IncompatibleAddressableAreaError: Cannot use Temperature Module in D3, not compatible with one or more of the following fixtures: Waste Chute", "errorCode": "4000", "errorInfo": {}, - "errorType": "IncompatibleAddressableAreaError", - "wrappedErrors": [] + "errorType": "ProtocolCommandFailedError", + "wrappedErrors": [ + { + "detail": "Cannot use Temperature Module in D3, not compatible with one or more of the following fixtures: Waste Chute", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "IncompatibleAddressableAreaError", + "wrappedErrors": [] + } + ] } ] } ], "files": [ { - "name": "Flex_P1000_96_TM_2_16_AnalysisError_ModuleAndWasteChuteConflict.py", + "name": "Flex_X_v2_16_P1000_96_TM_ModuleAndWasteChuteConflict.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[cac08da081][Flex_None_None_TC_2_15_verifyThermocyclerLoadedSlots].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f639acc89d][Flex_S_v2_15_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots].json similarity index 95% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[cac08da081][Flex_None_None_TC_2_15_verifyThermocyclerLoadedSlots].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f639acc89d][Flex_S_v2_15_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots].json index ffe74376eeb..f2c22e7db81 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[cac08da081][Flex_None_None_TC_2_15_verifyThermocyclerLoadedSlots].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f639acc89d][Flex_S_v2_15_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots].json @@ -137,7 +137,7 @@ "errorInfo": { "args": "()", "class": "AssertionError", - "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_None_None_TC_2_15_verifyThermocyclerLoadedSlots.py\", line 13, in run\n" + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 124, in run_python\n exec(\"run(__context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_S_v2_15_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots.py\", line 13, in run\n" }, "errorType": "PythonException", "wrappedErrors": [] @@ -147,7 +147,7 @@ ], "files": [ { - "name": "Flex_None_None_TC_2_15_verifyThermocyclerLoadedSlots.py", + "name": "Flex_S_v2_15_NO_PIPETTES_TC_verifyThermocyclerLoadedSlots.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[298e1dd4db][Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLidClips].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f7085d7134][Flex_X_v2_16_P1000_96_TC_pipetteCollisionWithThermocyclerLidClips].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[298e1dd4db][Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLidClips].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f7085d7134][Flex_X_v2_16_P1000_96_TC_pipetteCollisionWithThermocyclerLidClips].json index c2f8a537b65..fd28108213d 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[298e1dd4db][Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLidClips].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f7085d7134][Flex_X_v2_16_P1000_96_TC_pipetteCollisionWithThermocyclerLidClips].json @@ -1324,7 +1324,7 @@ ], "files": [ { - "name": "Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLidClips.py", + "name": "Flex_X_v2_16_P1000_96_TC_pipetteCollisionWithThermocyclerLidClips.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[afe15b729c][Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f834b97da1][Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_DeckConfiguration1].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[afe15b729c][Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f834b97da1][Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_DeckConfiguration1].json index 49900d0964c..d68d08d41ae 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[afe15b729c][Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f834b97da1][Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_DeckConfiguration1].json @@ -12402,7 +12402,7 @@ "notes": [], "params": { "addressableAreaName": "movableTrashC1", - "alternateDropLocation": false, + "alternateDropLocation": true, "forceDirect": false, "ignoreTipConfiguration": true, "offset": { @@ -12413,7 +12413,7 @@ }, "result": { "position": { - "x": 22.25, + "x": 54.25, "y": 150.0, "z": 40.0 } @@ -12661,7 +12661,7 @@ "notes": [], "params": { "addressableAreaName": "movableTrashD1", - "alternateDropLocation": false, + "alternateDropLocation": true, "forceDirect": false, "ignoreTipConfiguration": true, "offset": { @@ -12672,7 +12672,7 @@ }, "result": { "position": { - "x": 22.25, + "x": 54.25, "y": 43.0, "z": 40.0 } @@ -13016,7 +13016,7 @@ "errors": [], "files": [ { - "name": "Flex_P1000_96_GRIPPER_HS_TM_TC_MB_2_16_DeckConfiguration1.py", + "name": "Flex_S_v2_16_P1000_96_GRIP_HS_MB_TC_TM_DeckConfiguration1.py", "role": "main" }, { diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f88b7d6e30][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_display_name].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f88b7d6e30][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_display_name].json new file mode 100644 index 00000000000..f39ac142b59 --- /dev/null +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f88b7d6e30][Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_display_name].json @@ -0,0 +1,74 @@ +{ + "commands": [ + { + "commandType": "home", + "notes": [], + "params": {}, + "result": {}, + "status": "succeeded" + } + ], + "config": { + "apiVersion": [ + 2, + 18 + ], + "protocolType": "python" + }, + "errors": [ + { + "detail": "ParameterNameError [line 30]: Display name must be a string and at most 30 characters.", + "errorCode": "4000", + "errorInfo": {}, + "errorType": "ExceptionInProtocolError", + "wrappedErrors": [ + { + "detail": "opentrons.protocols.parameters.types.ParameterNameError: Display name must be a string and at most 30 characters.", + "errorCode": "4000", + "errorInfo": { + "args": "('Display name must be a string and at most 30 characters.',)", + "class": "ParameterNameError", + "traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line 80, in _parse_and_set_parameters\n exec(\"add_parameters(__param_context)\", new_globs)\n\n File \"\", line 1, in \n\n File \"Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_display_name.py\", line 30, in add_parameters\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/_parameter_context.py\", line 56, in add_int\n parameter = parameter_definition.create_int_parameter(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 178, in create_int_parameter\n return ParameterDefinition(\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/parameter_definition.py\", line 56, in __init__\n self._display_name = validation.ensure_display_name(display_name)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/parameters/validation.py\", line 33, in ensure_display_name\n raise ParameterNameError(\n" + }, + "errorType": "PythonException", + "wrappedErrors": [] + } + ] + } + ], + "files": [ + { + "name": "Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP_Override_wrong_type_in_display_name.py", + "role": "main" + }, + { + "name": "cpx_4_tuberack_100ul.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_1000ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_200ul_rss.json", + "role": "labware" + }, + { + "name": "opentrons_ot3_96_tiprack_50ul_rss.json", + "role": "labware" + }, + { + "name": "sample_labware.json", + "role": "labware" + } + ], + "labware": [], + "liquids": [], + "metadata": { + "protocolName": "Description Too Long 2.18" + }, + "modules": [], + "pipettes": [], + "robotType": "OT-3 Standard", + "runTimeParameters": [] +} diff --git a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f1a979fd7b][OT2_P300M_P20S_TC_HS_TM_2_16_dispense_changes].json b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[fc60ef9cbd][OT2_S_v2_16_P300M_P20S_HS_TC_TM_dispense_changes].json similarity index 99% rename from app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f1a979fd7b][OT2_P300M_P20S_TC_HS_TM_2_16_dispense_changes].json rename to app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[fc60ef9cbd][OT2_S_v2_16_P300M_P20S_HS_TC_TM_dispense_changes].json index 778a4b220f7..e98baefe075 100644 --- a/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[f1a979fd7b][OT2_P300M_P20S_TC_HS_TM_2_16_dispense_changes].json +++ b/app-testing/tests/__snapshots__/analyses_snapshot_test/test_analysis_snapshot[fc60ef9cbd][OT2_S_v2_16_P300M_P20S_HS_TC_TM_dispense_changes].json @@ -2965,7 +2965,7 @@ "errors": [], "files": [ { - "name": "OT2_P300M_P20S_TC_HS_TM_2_16_dispense_changes.py", + "name": "OT2_S_v2_16_P300M_P20S_HS_TC_TM_dispense_changes.py", "role": "main" }, { diff --git a/app-testing/tests/analyses_snapshot_test.py b/app-testing/tests/analyses_snapshot_test.py index cc4c2498ae3..0cecaff8940 100644 --- a/app-testing/tests/analyses_snapshot_test.py +++ b/app-testing/tests/analyses_snapshot_test.py @@ -1,16 +1,19 @@ import json import os from pathlib import Path -from typing import Any, List +from typing import Any, List, Optional import pytest from automation.data.protocol import Protocol -from automation.data.protocols import Protocols +from automation.data.protocol_registry import ProtocolRegistry from citools.generate_analyses import ANALYSIS_SUFFIX, generate_analyses_from_test +from rich.console import Console from syrupy.extensions.json import JSONSnapshotExtension from syrupy.filters import props from syrupy.types import SerializableData +console = Console() + # not included in the snapshot exclude = props( "id", @@ -38,19 +41,11 @@ def snapshot_json(snapshot_exclude: SerializableData) -> SerializableData: return snapshot_exclude.with_defaults(extension_class=JSONSnapshotExtension) -def what_protocols() -> List[Protocol]: - protocols: Protocols = Protocols() - protocols_to_test: str = os.getenv("APP_ANALYSIS_TEST_PROTOCOLS", "upload_protocol") - tests: list[(Protocol)] = [] - for protocol_name in [x.strip() for x in protocols_to_test.split(",")]: - tests.append((getattr(protocols, protocol_name))) - return tests - - @pytest.fixture(scope="session") def analyze_protocols() -> None: """Use the environment variable to select which protocols are used in the test.""" - tests = what_protocols() + protocol_registry: ProtocolRegistry = ProtocolRegistry() + tests = protocol_registry.protocols_to_test # Generate target analyses if not tests: exit("No protocols to test.") @@ -86,16 +81,17 @@ def sort_all_lists(d: Any, sort_key: str | None = None) -> Any: return d -# Read in what protocols to test from the environment variable -# APP_ANALYSIS_TEST_PROTOCOLS -# Generate all the analyses for the target version of the Opentrons repository -# Compare the analyses to the snapshots +protocol_registry: ProtocolRegistry = ProtocolRegistry() +protocols_to_test: Optional[List[Protocol]] = protocol_registry.protocols_to_test + +if not protocols_to_test: + exit("No protocols to test.") @pytest.mark.parametrize( "protocol", - what_protocols(), - ids=[x.short_sha for x in what_protocols()], + protocols_to_test, + ids=[x.short_sha for x in protocols_to_test], ) def test_analysis_snapshot(analyze_protocols: None, snapshot_json: SerializableData, protocol: Protocol) -> None: target = os.getenv("TARGET") @@ -104,13 +100,14 @@ def test_analysis_snapshot(analyze_protocols: None, snapshot_json: SerializableD analysis = Path( Path(__file__).parent.parent, "analysis_results", - f"{protocol.file_name}_{target}_{ANALYSIS_SUFFIX}", + f"{protocol.file_stem}_{target}_{ANALYSIS_SUFFIX}", ) + console.print(f"Analysis file: {analysis}") if analysis.exists(): with open(analysis, "r") as f: data = json.load(f) - print(f"Test name: {protocol.file_name}") + print(f"Test name: {protocol.file_stem}") data = sort_all_lists(data, sort_key="name") - assert snapshot_json(name=protocol.file_name) == data + assert snapshot_json(name=protocol.file_stem) == data else: raise AssertionError(f"Analysis file not found: {analysis}") diff --git a/app-testing/tests/calibrate_test.py b/app-testing/tests/calibrate_test.py index 0c246a11c53..52bac253b93 100644 --- a/app-testing/tests/calibrate_test.py +++ b/app-testing/tests/calibrate_test.py @@ -1,4 +1,5 @@ """Test the initial state the application with various setups.""" + import time from typing import List diff --git a/app-testing/tests/labware_landing_test.py b/app-testing/tests/labware_landing_test.py index 1ed77bcc8bc..73dfd1c87ca 100644 --- a/app-testing/tests/labware_landing_test.py +++ b/app-testing/tests/labware_landing_test.py @@ -1,4 +1,5 @@ """Test the Labware Landing of the page.""" + from pathlib import Path from typing import Dict, List diff --git a/app-testing/tests/lpc_test.py b/app-testing/tests/lpc_test.py index 47adcfda955..ebdce66ce0f 100644 --- a/app-testing/tests/lpc_test.py +++ b/app-testing/tests/lpc_test.py @@ -1,4 +1,5 @@ """todo these tests for refactoring""" + # flake8: noqa import time from pathlib import Path diff --git a/app-testing/tests/protocol_analyze_test.py b/app-testing/tests/protocol_analyze_test.py index 09e1f5b9cd0..cce6f0434f0 100644 --- a/app-testing/tests/protocol_analyze_test.py +++ b/app-testing/tests/protocol_analyze_test.py @@ -1,9 +1,10 @@ """Test the Protocol Landing of the page.""" -import os + +from typing import List, Optional import pytest from automation.data.protocol import Protocol -from automation.data.protocols import Protocols +from automation.data.protocol_registry import ProtocolRegistry from automation.driver.drag_drop import drag_and_drop_file from automation.menus.left_menu import LeftMenu from automation.pages.labware_landing import LabwareLanding @@ -13,33 +14,6 @@ from selenium.webdriver.remote.webelement import WebElement -def _what_protocols() -> list[Protocol]: - """Use the environment variable to select which protocols are used in the test.""" - protocols: Protocols = Protocols() - protocols_to_test: str = os.getenv("APP_ANALYSIS_TEST_PROTOCOLS", "upload_protocol") - tests: list[Protocol] = [] - for protocol_name in [x.strip() for x in protocols_to_test.split(",") if len(x.strip()) > 0]: - protocol = getattr(protocols, protocol_name) - tests.append( - # https://docs.pytest.org/en/7.1.x/reference/reference.html#pytest-param - # pytest.param returns a special ParamterSet type. But when pytest runs - # the test, it will be a Protocol type. Don't feel like fighting mypy. - pytest.param( # type: ignore[arg-type] - protocol, - id=protocol.protocol_name, - # https://docs.pytest.org/en/7.1.x/reference/reference.html#pytest-mark-xfail - marks=pytest.mark.xfail( - condition=protocol.expected_test_failure, - reason=protocol.expected_test_reason, - raises=AssertionError, - run=True, - strict=True, - ), - ) - ) - return tests - - def get_error_text(protocol_landing: ProtocolLanding, error_link: WebElement) -> str: protocol_landing.base.click_webelement(error_link) error_details = protocol_landing.get_popout_error().text @@ -47,7 +21,15 @@ def get_error_text(protocol_landing: ProtocolLanding, error_link: WebElement) -> return error_details -@pytest.mark.parametrize("protocol", _what_protocols()) +protocol_registry: ProtocolRegistry = ProtocolRegistry() +protocols_to_test: Optional[List[Protocol]] = protocol_registry.protocols_to_test + +if not protocols_to_test: + exit("No protocols to test.") + + +@pytest.mark.skip(reason="This test is deprecated in place of the test_analyses test.") +@pytest.mark.parametrize("protocol", protocols_to_test, ids=[x.short_sha for x in protocols_to_test]) def test_analyses( driver: WebDriver, console: Console, @@ -105,8 +87,8 @@ def test_analyses( # Verifying elements on Protocol Landing Page # todo fix next line needs to be safe and print name not found - assert protocol_landing.get_deckMap_protocol_landing(protocol_name=protocol.protocol_name).is_displayed() - assert protocol_landing.get_protocol_name_text_protocol_landing(protocol_name=protocol.protocol_name) == protocol.protocol_name + # assert protocol_landing.get_deckMap_protocol_landing(protocol_name=protocol.protocol_name).is_displayed() + # assert protocol_landing.get_protocol_name_text_protocol_landing(protocol_name=protocol.protocol_name) == protocol.protocol_name # TODO validate robot diff --git a/app-testing/tests/protocol_landing_test.py b/app-testing/tests/protocol_landing_test.py index b003b3495fe..07e8801d5f7 100644 --- a/app-testing/tests/protocol_landing_test.py +++ b/app-testing/tests/protocol_landing_test.py @@ -1,4 +1,5 @@ """Test the Protocol Landing of the page.""" + import time from pathlib import Path from typing import Dict diff --git a/app/package.json b/app/package.json index 5097851c9ff..30836e11b8e 100644 --- a/app/package.json +++ b/app/package.json @@ -49,6 +49,7 @@ "react-error-boundary": "^4.0.10", "react-i18next": "13.5.0", "react-intersection-observer": "^8.33.1", + "react-markdown": "9.0.1", "react-redux": "8.1.2", "react-router-dom": "5.3.4", "react-select": "5.4.0", @@ -57,8 +58,6 @@ "redux": "4.0.5", "redux-observable": "1.1.0", "redux-thunk": "2.3.0", - "remark": "9.0.0", - "remark-react": "4.0.3", "reselect": "4.0.0", "rxjs": "^6.5.1", "semver": "5.5.0", diff --git a/app/src/App/DesktopApp.tsx b/app/src/App/DesktopApp.tsx index f42ef7e0e80..ffa50727da1 100644 --- a/app/src/App/DesktopApp.tsx +++ b/app/src/App/DesktopApp.tsx @@ -1,6 +1,7 @@ import * as React from 'react' import { Redirect, Route, Switch, useRouteMatch } from 'react-router-dom' import { ErrorBoundary } from 'react-error-boundary' +import { I18nextProvider } from 'react-i18next' import { Box, @@ -11,6 +12,7 @@ import { import { ApiHostProvider } from '@opentrons/react-api-client' import NiceModal from '@ebay/nice-modal-react' +import { i18n } from '../i18n' import { Alerts } from '../organisms/Alerts' import { Breadcrumbs } from '../organisms/Breadcrumbs' import { ToasterOven } from '../organisms/ToasterOven' @@ -101,45 +103,47 @@ export const DesktopApp = (): JSX.Element => { return ( - - - - - - - - {desktopRoutes.map( - ({ Component, exact, path }: RouteProps) => { - return ( - - - - - - - - ) - } - )} - - - - - - - - + + + + + + + + + {desktopRoutes.map( + ({ Component, exact, path }: RouteProps) => { + return ( + + + + + + + + ) + } + )} + + + + + + + + + ) } diff --git a/app/src/App/Navbar.tsx b/app/src/App/Navbar.tsx index 8397927392f..f9e79ea65e9 100644 --- a/app/src/App/Navbar.tsx +++ b/app/src/App/Navbar.tsx @@ -28,6 +28,7 @@ import { NAV_BAR_WIDTH } from './constants' import type { RouteProps } from './types' const SALESFORCE_HELP_LINK = 'https://support.opentrons.com/s/' +const PROJECT: string = _OPENTRONS_PROJECT_ const NavbarLink = styled(NavLink)` color: ${COLORS.white}; @@ -128,7 +129,7 @@ export function Navbar({ routes }: { routes: RouteProps[] }): JSX.Element { alignSelf={ALIGN_STRETCH} > {navRoutes.map(({ name, navLinkTo }: RouteProps) => ( diff --git a/app/src/App/OnDeviceDisplayApp.tsx b/app/src/App/OnDeviceDisplayApp.tsx index c9923e1aea3..1459ff5071f 100644 --- a/app/src/App/OnDeviceDisplayApp.tsx +++ b/app/src/App/OnDeviceDisplayApp.tsx @@ -16,6 +16,7 @@ import { ApiHostProvider } from '@opentrons/react-api-client' import NiceModal from '@ebay/nice-modal-react' import { SleepScreen } from '../atoms/SleepScreen' +import { OnDeviceLocalizationProvider } from '../LocalizationProvider' import { ToasterOven } from '../organisms/ToasterOven' import { MaintenanceRunTakeover } from '../organisms/TakeoverModal' import { FirmwareUpdateTakeover } from '../organisms/FirmwareUpdateModal/FirmwareUpdateTakeover' @@ -31,6 +32,7 @@ import { RobotDashboard } from '../pages/RobotDashboard' import { RobotSettingsDashboard } from '../pages/RobotSettingsDashboard' import { ProtocolDashboard } from '../pages/ProtocolDashboard' import { ProtocolDetails } from '../pages/ProtocolDetails' +import { QuickTransferFlow } from '../organisms/QuickTransferFlow' import { RunningProtocol } from '../pages/RunningProtocol' import { RunSummary } from '../pages/RunSummary' import { UpdateRobot } from '../pages/UpdateRobot/UpdateRobot' @@ -66,13 +68,13 @@ export const ON_DEVICE_DISPLAY_PATHS = [ '/emergency-stop', '/instruments', '/instruments/:mount', - '/loading', '/network-setup', '/network-setup/ethernet', '/network-setup/usb', '/network-setup/wifi', '/protocols', '/protocols/:protocolId', + '/quick-transfer', '/robot-settings', '/robot-settings/rename-robot', '/robot-settings/update-robot', @@ -97,8 +99,6 @@ function getPathComponent( return case '/instruments/:mount': return - case '/loading': - return case '/network-setup': return case '/network-setup/ethernet': @@ -111,6 +111,8 @@ function getPathComponent( return case '/protocols/:protocolId': return + case `/quick-transfer`: + return case '/robot-settings': return case '/robot-settings/rename-robot': @@ -151,12 +153,75 @@ export const OnDeviceDisplayApp = (): JSX.Element => { } const dispatch = useDispatch() const isIdle = useIdle(sleepTime, options) + + React.useEffect(() => { + if (isIdle) { + dispatch(updateBrightness(TURN_OFF_BACKLIGHT)) + } else { + dispatch( + updateConfigValue( + 'onDeviceDisplaySettings.brightness', + userSetBrightness + ) + ) + } + }, [dispatch, isIdle, userSetBrightness]) + + // TODO (sb:6/12/23) Create a notification manager to set up preference and order of takeover modals + return ( + + + + + + {isIdle ? ( + + ) : ( + <> + + + + + + + + + + + + )} + + + + + + + ) +} + +const getTargetPath = (unfinishedUnboxingFlowRoute: string | null): string => { + if (unfinishedUnboxingFlowRoute != null) { + return unfinishedUnboxingFlowRoute + } + + return '/dashboard' +} + +// split to a separate function because scrollRef rerenders on every route change +// this avoids rerendering parent providers as well +export function OnDeviceDisplayAppRoutes(): JSX.Element { const [currentNode, setCurrentNode] = React.useState(null) const scrollRef = React.useCallback((node: HTMLElement | null) => { setCurrentNode(node) }, []) const isScrolling = useScrolling(currentNode) + const { unfinishedUnboxingFlowRoute } = useSelector( + getOnDeviceDisplaySettings + ) + + const targetPath = getTargetPath(unfinishedUnboxingFlowRoute) + const TOUCH_SCREEN_STYLE = css` position: ${POSITION_RELATIVE}; width: 100%; @@ -176,54 +241,18 @@ export const OnDeviceDisplayApp = (): JSX.Element => { } ` - React.useEffect(() => { - if (isIdle) { - dispatch(updateBrightness(TURN_OFF_BACKLIGHT)) - } else { - dispatch( - updateConfigValue( - 'onDeviceDisplaySettings.brightness', - userSetBrightness - ) - ) - } - }, [dispatch, isIdle, userSetBrightness]) - - // TODO (sb:6/12/23) Create a notification manager to set up preference and order of takeover modals return ( - - - - {isIdle ? ( - - ) : ( - <> - - - - - - - - {ON_DEVICE_DISPLAY_PATHS.map(path => ( - - - - {getPathComponent(path)} - - - ))} - - - - - - - )} - - - - + + {ON_DEVICE_DISPLAY_PATHS.map(path => ( + + + + {getPathComponent(path)} + + + ))} + {targetPath != null && } + ) } diff --git a/app/src/App/OnDeviceDisplayAppFallback.tsx b/app/src/App/OnDeviceDisplayAppFallback.tsx index 6a345c1735e..0e48a31e565 100644 --- a/app/src/App/OnDeviceDisplayAppFallback.tsx +++ b/app/src/App/OnDeviceDisplayAppFallback.tsx @@ -27,7 +27,7 @@ import type { ModalHeaderBaseProps } from '../molecules/Modal/types' export function OnDeviceDisplayAppFallback({ error, }: FallbackProps): JSX.Element { - const { t } = useTranslation('app_settings') + const { t } = useTranslation(['app_settings', 'branded']) const trackEvent = useTrackEvent() const dispatch = useDispatch() const localRobot = useSelector(getLocalRobot) @@ -59,7 +59,9 @@ export function OnDeviceDisplayAppFallback({ alignItems={ALIGN_CENTER} justifyContent={JUSTIFY_CENTER} > - {t('error_boundary_description')} + + {t('branded:error_boundary_description')} + { + const actual = await vi.importActual('@opentrons/react-api-client') + return { + ...actual, + useRobotSettingsQuery: () => + (({ + data: { settings: [] }, + } as unknown) as UseQueryResult), + } +}) +vi.mock('../../LocalizationProvider') vi.mock('../../pages/Welcome') vi.mock('../../pages/NetworkSetupMenu') vi.mock('../../pages/ConnectViaEthernet') @@ -45,7 +60,6 @@ vi.mock('../../pages/InstrumentsDashboard') vi.mock('../../pages/RunningProtocol') vi.mock('../../pages/RunSummary') vi.mock('../../pages/NameRobot') -vi.mock('../../pages/InitialLoadingScreen') vi.mock('../../pages/EmergencyStop') vi.mock('../../pages/DeckConfiguration') vi.mock('../../redux/config') @@ -73,7 +87,7 @@ const render = (path = '/') => { describe('OnDeviceDisplayApp', () => { beforeEach(() => { vi.mocked(getOnDeviceDisplaySettings).mockReturnValue(mockSettings as any) - vi.mocked(getIsShellReady).mockReturnValue(false) + vi.mocked(getIsShellReady).mockReturnValue(true) vi.mocked(useCurrentRunRoute).mockReturnValue(null) vi.mocked(getLocalRobot).mockReturnValue(mockConnectedRobot) vi.mocked(useNotifyCurrentMaintenanceRun).mockReturnValue({ @@ -83,6 +97,12 @@ describe('OnDeviceDisplayApp', () => { }, }, } as any) + // TODO(bh, 2024-03-27): implement testing of branded and anonymous i18n, but for now pass through + vi.mocked( + OnDeviceLocalizationProvider + ).mockImplementation((props: OnDeviceLocalizationProviderProps) => ( + <>{props.children} + )) }) afterEach(() => { vi.resetAllMocks() @@ -140,9 +160,16 @@ describe('OnDeviceDisplayApp', () => { render('/runs/my-run-id/summary') expect(vi.mocked(RunSummary)).toHaveBeenCalled() }) - it('renders the loading screen on mount', () => { - render('/loading') - expect(vi.mocked(InitialLoadingScreen)).toHaveBeenCalled() + it('renders the localization provider and not the loading screen when app-shell is ready', () => { + render('/') + expect(vi.mocked(OnDeviceLocalizationProvider)).toHaveBeenCalled() + expect(screen.queryByLabelText('loading indicator')).toBeNull() + }) + it('renders the loading screen when app-shell is not ready', () => { + vi.mocked(getIsShellReady).mockReturnValue(false) + render('/') + screen.getByLabelText('loading indicator') + expect(vi.mocked(OnDeviceLocalizationProvider)).not.toHaveBeenCalled() }) it('renders EmergencyStop component from /emergency-stop', () => { render('/emergency-stop') diff --git a/app/src/LocalizationProvider.tsx b/app/src/LocalizationProvider.tsx new file mode 100644 index 00000000000..e2a30c95cd7 --- /dev/null +++ b/app/src/LocalizationProvider.tsx @@ -0,0 +1,53 @@ +import * as React from 'react' +import { I18nextProvider } from 'react-i18next' +import reduce from 'lodash/reduce' + +import { resources } from './assets/localization' +import { useIsOEMMode } from './resources/robot-settings/hooks' +import { i18n, i18nCb, i18nConfig } from './i18n' + +export interface OnDeviceLocalizationProviderProps { + children?: React.ReactNode +} + +const BRANDED_RESOURCE = 'branded' +const ANONYMOUS_RESOURCE = 'anonymous' + +// TODO(bh, 2024-03-26): anonymization limited to ODD for now, may change in future OEM phases +export function OnDeviceLocalizationProvider( + props: OnDeviceLocalizationProviderProps +): JSX.Element | null { + const isOEMMode = useIsOEMMode() + + // iterate through language resources, nested files, substitute anonymous file for branded file for OEM mode + const anonResources = reduce( + resources, + (acc, resource, language) => { + const anonFiles = reduce( + resource, + (acc, file, fileName) => { + if (fileName === BRANDED_RESOURCE && isOEMMode) { + return acc + } else if (fileName === ANONYMOUS_RESOURCE) { + return isOEMMode ? { ...acc, [BRANDED_RESOURCE]: file } : acc + } else { + return { ...acc, [fileName]: file } + } + }, + {} + ) + return { ...acc, [language]: anonFiles } + }, + {} + ) + + const anonI18n = i18n.createInstance( + { + ...i18nConfig, + resources: anonResources, + }, + i18nCb + ) + + return {props.children} +} diff --git a/app/src/assets/images/on-device-display/multiple_modules_modal.png b/app/src/assets/images/on-device-display/multiple_modules_modal.png deleted file mode 100644 index 721c7cb11f7..00000000000 Binary files a/app/src/assets/images/on-device-display/multiple_modules_modal.png and /dev/null differ diff --git a/app/src/assets/images/staging_area_magnetic_block_gen_1.png b/app/src/assets/images/staging_area_magnetic_block_gen_1.png new file mode 100644 index 00000000000..94ef05f08ed Binary files /dev/null and b/app/src/assets/images/staging_area_magnetic_block_gen_1.png differ diff --git a/app/src/assets/localization/en/anonymous.json b/app/src/assets/localization/en/anonymous.json new file mode 100644 index 00000000000..fc62241e0df --- /dev/null +++ b/app/src/assets/localization/en/anonymous.json @@ -0,0 +1,74 @@ +{ + "a_robot_software_update_is_available": "A robot software update is required to run protocols with this version of the desktop app. Go to Robot", + "about_flex_gripper": "About Gripper", + "alternative_security_types_description": "The robot supports connecting to various enterprise access points. Connect via USB and finish setup in the desktop app.", + "calibration_block_description": "This block is a specially made tool that fits perfectly on your deck and helps with calibration.If you do not have a Calibration Block, please email support so we can send you one. In your message, be sure to include your name, company or institution name, and shipping address. While you wait for the block to arrive, you can use the flat surface on the trash bin of your robot instead.", + "calibration_on_opentrons_tips_is_important": "It’s extremely important to perform this calibration using the tips and tip racks specified above, as the robot determines accuracy based on the known measurements of these tips.", + "choose_what_data_to_share": "Choose what robot data to share.", + "computer_in_app_is_controlling_robot": "A network-connected computer is currently controlling this robot.", + "confirm_terminate": "This will immediately stop the activity begun on a computer. You, or another user, may lose progress or see an error on that computer.", + "connect_and_screw_in_gripper": "Connect and secure gripper", + "connect_via_usb_description_3": "3. Launch the robot app on the connected computer to continue.", + "connection_description_usb": "Connect directly to a computer.", + "connection_lost_description": "The app is unable to communicate with this robot right now. Double check the USB or Wi-Fi connection to the robot and then try to reconnect.", + "contact_information": "Contact support for assistance.", + "contact_support_for_connection_help": "If none of these work, contact support for help (via the question mark link in this app, or by emailing {{support_email}}.)", + "deck_fixture_setup_modal_bottom_description": "For details on installing different fixture types, contact support.", + "delete_protocol_from_app": "Delete the protocol, make changes to address the error, and resend the protocol to this robot from the desktop app.", + "error_boundary_description": "You need to restart the touchscreen. Contact support for assistance.", + "estop_pressed_description": "First, safely clear the deck of any labware or spills. Then, twist the E-stop button clockwise. Finally, have the robot move the gantry to its home position.", + "find_your_robot": "Find your robot in the Devices section of the app to install software updates.", + "firmware_update_download_logs": "Contact support for assistance.", + "general_error_message": "If you keep getting this message, try restarting your app and robot. If this does not resolve the issue, contact support.", + "gripper_still_attached": "Gripper still attached", + "gripper_successfully_attached_and_calibrated": "Gripper successfully attached and calibrated", + "gripper_successfully_calibrated": "Gripper successfully calibrated", + "gripper_successfully_detached": "Gripper successfully detached", + "gripper": "Gripper", + "help_us_improve_send_error_report": "Help us improve your experience by sending an error report to support", + "ip_description_second": "Work with your network administrator to assign a static IP address to the robot.", + "learn_uninstalling": "Learn more about uninstalling the app", + "loosen_screws_and_detach": "Loosen screws and detach gripper", + "modal_instructions": "For step-by-step instructions on setting up your module, consult the Quickstart Guide that came in its box.", + "module_calibration_failed": "Module calibration was unsuccessful. Make sure the calibration adapter is fully seated on the module and try again. If you still have trouble, contact support.{{error}}", + "module_calibration_get_started": "To get started, remove labware from the deck and clean up the working area to make the calibration easier. Also gather the needed equipment shown to the right.The calibration adapter came with your module. The pipette probe came with your pipette.", + "module_error_contact_support": "Try powering the module off and on again. If the error persists, contact support.", + "network_setup_menu_description": "You’ll use this connection to run software updates and load protocols onto your robot.", + "oem_mode_description": "Enable OEM Mode to remove all instances of Opentrons from the Flex touchscreen.", + "opentrons_app_successfully_updated": "The app was successfully updated.", + "opentrons_app_update": "app update", + "opentrons_app_update_available": "App Update Available", + "opentrons_app_update_available_variation": "An app update is available.", + "opentrons_app_will_use_interpreter": "If specified, the app will use the Python interpreter at this path instead of the default bundled Python interpreter.", + "opentrons_cares_about_privacy": "We care about your privacy. We anonymize all data and only use it to improve our products.", + "opentrons_def": "Verified Definition", + "opentrons_labware_def": "Verified labware definition", + "opentrons_tip_racks_recommended": "Opentrons tip racks are highly recommended. Accuracy cannot be guaranteed with other tip racks.", + "opentrons_tip_rack_name": "opentrons", + "previous_releases": "View previous releases", + "receive_alert": "Receive an alert when a software update is available.", + "restore_description": "Reverting to previous software versions is not recommended, but you can access previous releases below. For best results, uninstall the existing app and remove its configuration files before installing the previous version.", + "robot_server_version_ot3_description": "The robot software includes the robot server and the touchscreen display interface.", + "robot_software_update_required": "A robot software update is required to run protocols with this version of the app.", + "run_failed_modal_description_desktop": "Contact support for assistance.", + "secure_labware_explanation_magnetic_module": "Ensure that your labware locks to the Magnetic Module by adjusting the black plate bracket on top of the module. There are two sizes of plate brackets supplied with your module: standard and deep well. These brackets can be removed and swapped by unscrewing the module's thumb screw (the silver knob on the front).", + "secure_labware_explanation_thermocycler": "Secure your labware to the Thermocycler Module by closing its latch. Doing so ensures level and accurate plate placement for optimal results.", + "send_a_protocol_to_store": "Send a protocol to the robot to get started.", + "setup_instructions_description": "For step-by-step instructions on setting up your module, consult the Quickstart Guide that came in its box.", + "share_app_analytics": "Share App Analytics", + "share_app_analytics_description": "Help improve this product by automatically sending anonymous diagnostics and usage data.", + "share_display_usage_description": "Data on how you interact with the robot's touchscreen.", + "share_logs_with_opentrons": "Share robot logs", + "share_logs_with_opentrons_description": "Help improve this product by automatically sending anonymous robot logs. These logs are used to troubleshoot robot issues and spot error trends.", + "show_labware_offset_snippets_description": "Only for users who need to apply labware offset data outside of the app. When enabled, code snippets for Jupyter Notebook and SSH are available during protocol setup.", + "something_seems_wrong": "There may be a problem with your pipette. Exit setup and contact support for assistance.", + "these_are_advanced_settings": "These are advanced settings. Please do not attempt to adjust without assistance from support. Changing these settings may affect the lifespan of your pipette.These settings do not override any pipette settings defined in protocols.", + "update_requires_restarting_app": "Updating requires restarting the app.", + "update_robot_software_description": "Bypass the auto-update process and update the robot software manually.", + "update_robot_software_link": "Launch software update page", + "versions_sync": "Learn more about keeping the app and robot software in sync", + "view_latest_release_notes_at": "Please contact support for release notes.", + "want_to_help_out": "Want to help out?", + "welcome_title": "Welcome!", + "why_use_lpc": "Labware Position Check is intended to correct for minor variances. Don't use Labware Position Check to compensate for large positional adjustments. Needing to set large labware offsets could indicate a problem with robot calibration." +} diff --git a/app/src/assets/localization/en/app_settings.json b/app/src/assets/localization/en/app_settings.json index 18e3eef9e8a..389854a8b33 100644 --- a/app/src/assets/localization/en/app_settings.json +++ b/app/src/assets/localization/en/app_settings.json @@ -11,16 +11,12 @@ "additional_folder_location": "Additional Source Folder", "additional_labware_folder_title": "Additional Custom Labware Source Folder", "advanced": "Advanced", - "allow_sending_all_protocols_to_ot3": "Allow Sending All Protocols to Opentrons Flex", - "allow_sending_all_protocols_to_ot3_description": "Enable the \"Send to Opentrons Flex\" menu item for each imported protocol, even if protocol analysis fails or does not recognize it as designed for the Opentrons Flex.", - "analytics_description": "Help Opentrons improve its products and services by automatically sending anonymous diagnostics and usage data.", "app_changes": "App Changes in ", "app_settings": "App Settings", "bug_fixes": "Bug Fixes", "cal_block": "Always use calibration block to calibrate", "change_folder_button": "Change labware source folder", "channel": "Channel", - "choose_what_data_to_share": "Choose what data to share with Opentrons.", "clear_confirm": "Clear unavailable robots", "clear_robots_button": "Clear unavailable robots list", "clear_robots_description": "Clear the list of unavailable robots on the Devices page. This action cannot be undone.", @@ -35,7 +31,6 @@ "download_update": "Downloading update...", "enable_dev_tools": "Developer Tools", "enable_dev_tools_description": "Enabling this setting opens Developer Tools on app launch, enables additional logging and gives access to feature flags.", - "error_boundary_description": "You need to restart the touchscreen. Then download the robot logs from the Opentrons App and send them to support@opentrons.com for assistance.", "error_boundary_desktop_app_description": "You need to reload the app. Contact support with the following error message:", "error_boundary_title": "An unknown error has occurred", "feature_flags": "Feature Flags", @@ -46,20 +41,12 @@ "installing_update": "Installing update...", "ip_available": "Available", "ip_description_first": "Enter an IP address or hostname to connect to a robot.", - "ip_description_second": "Opentrons recommends working with your network administrator to assign a static IP address to the robot.", - "learn_uninstalling": "Learn more about uninstalling the Opentrons App", "manage_versions": "It is very important for the robot and app software to be on the same version. Manage the robot software versions via Robot Settings > Advanced.", "new_features": "New Features", "no_folder": "No additional source folder specified", "no_specified_folder": "No path specified", "no_unavail_robots_to_clear": "No unavailable robots to clear", "not_found": "Not Found", - "opentrons_app_successfully_updated": "The Opentrons App was successfully updated.", - "opentrons_app_update": "Opentrons App update", - "opentrons_app_update_available": "Opentrons App Update Available", - "opentrons_app_update_available_variation": "An Opentrons App update is available.", - "opentrons_app_will_use_interpreter": "If specified, the Opentrons App will use the Python interpreter at this path instead of the default bundled Python interpreter.", - "opentrons_cares_about_privacy": "Opentrons cares about your privacy. We anonymize all data and only use it to improve our products.", "opt_in": "Opt in", "opt_in_description": "Automatically send us anonymous diagnostics and usage data. We only use this information to improve our products.", "opt_out": "Opt out", @@ -68,29 +55,22 @@ "override_path_to_python": "Override Path to Python", "prevent_robot_caching": "Prevent Robot Caching", "prevent_robot_caching_description": "The app will immediately clear unavailable robots and will not remember unavailable robots while this is enabled. On networks with many robots, preventing caching may improve network performance at the expense of slower and less reliable robot discovery on app launch.", - "previous_releases": "View previous Opentrons releases", "privacy": "Privacy", "problem_during_update": "This update is taking longer than usual.", "prompt": "Always show the prompt to choose calibration block or trash bin", - "receive_alert": "Receive an alert when an Opentrons software update is available.", "release_notes": "Release notes", "reload_app": "Reload app", "remind_later": "Remind me later", "reset_to_default": "Reset to default", "restart_touchscreen": "Restart touchscreen", "restarting_app": "Download complete, restarting the app...", - "restore_description": "Opentrons does not recommend reverting to previous software versions, but you can access previous releases below. For best results, uninstall the existing app and remove its configuration files before installing the previous version.", "restore_previous": "See how to restore a previous software version", "searching": "Searching for 30s", "setup_connection": "Set up connection", - "share_app_analytics": "Share App Analytics with Opentrons", - "share_app_analytics_description": "Help Opentrons improve its products and services by automatically sending anonymous diagnostics and usage data.", "share_display_usage": "Share display usage", - "share_display_usage_description": "Data on how you interact with the touchscreen on Flex.", "share_robot_logs": "Share robot logs", "share_robot_logs_description": "Data on actions the robot does, like running protocols.", "show_labware_offset_snippets": "Show Labware Offset data code snippets", - "show_labware_offset_snippets_description": "Only for users who need to apply Labware Offset data outside of the Opentrons App. When enabled, code snippets for Jupyter Notebook and SSH are available during protocol setup.", "software_update_available": "Software Update Available", "software_version": "App Software Version", "successfully_deleted_unavail_robots": "Successfully deleted unavailable robots", @@ -104,7 +84,6 @@ "update_available": "Update available", "update_channel": "Update Channel", "update_description": "Stable receives the latest stable releases. Beta allows you to try out new in-progress features before they launch in Stable channel, but they have not completed testing yet.", - "update_requires_restarting": "Updating requires restarting the Opentrons App.", "usb_to_ethernet_adapter_description": "Description", "usb_to_ethernet_adapter_driver_version": "Driver Version", "usb_to_ethernet_adapter_info": "USB-to-Ethernet Adapter Information", @@ -116,11 +95,6 @@ "usb_to_ethernet_not_connected": "No USB-to-Ethernet adapter connected", "usb_to_ethernet_unknown_manufacturer": "Unknown Manufacturer", "usb_to_ethernet_unknown_product": "Unknown Adapter", - "versions_sync": "Learn more about keeping the Opentrons App and robot software in sync", - "view_change_log": "View Opentrons technical change log", - "view_issue_tracker": "View Opentrons issue tracker", - "view_release_notes": "View full Opentrons release notes", "view_software_update": "View software update", - "view_update": "View Update", - "want_to_help_out": "Want to help out Opentrons?" + "view_update": "View Update" } diff --git a/app/src/assets/localization/en/branded.json b/app/src/assets/localization/en/branded.json new file mode 100644 index 00000000000..ef9f1c79fa8 --- /dev/null +++ b/app/src/assets/localization/en/branded.json @@ -0,0 +1,74 @@ +{ + "a_robot_software_update_is_available": "A robot software update is required to run protocols with this version of the Opentrons App. Go to Robot", + "about_flex_gripper": "About Flex Gripper", + "alternative_security_types_description": "The Opentrons App supports connecting Flex to various enterprise access points. Connect via USB and finish setup in the app.", + "calibration_block_description": "This block is a specially made tool that fits perfectly on your deck and helps with calibration.If you do not have a Calibration Block, please email support@opentrons.com so we can send you one. In your message, be sure to include your name, company or institution name, and shipping address. While you wait for the block to arrive, you can use the flat surface on the trash bin of your robot instead.", + "calibration_on_opentrons_tips_is_important": "It’s extremely important to perform this calibration using the Opentrons tips and tip racks specified above, as the robot determines accuracy based on the known measurements of these tips.", + "choose_what_data_to_share": "Choose what data to share with Opentrons.", + "computer_in_app_is_controlling_robot": "A computer with the Opentrons App is currently controlling this robot.", + "confirm_terminate": "This will immediately stop the activity begun on a computer. You, or another user, may lose progress or see an error in the Opentrons App.", + "connect_and_screw_in_gripper": "Connect and secure Flex Gripper", + "connect_via_usb_description_3": "3. Launch the Opentrons App on the computer to continue.", + "connection_description_usb": "Connect directly to a computer (running the Opentrons App).", + "connection_lost_description": "The Opentrons App is unable to communicate with this robot right now. Double check the USB or Wi-Fi connection to the robot, then try to reconnect.", + "contact_information": "Download the robot logs from the Opentrons App and send it to support@opentrons.com for assistance.", + "contact_support_for_connection_help": "If none of these work, contact Opentrons Support for help (via the question mark link in this app, or by emailing {{support_email}}.)", + "deck_fixture_setup_modal_bottom_description": "For details on installing different fixture types, scan the QR code or search for “deck configuration” on support.opentrons.com", + "delete_protocol_from_app": "Delete the protocol, make changes to address the error, and resend the protocol to this robot from the Opentrons App.", + "error_boundary_description": "You need to restart the touchscreen. Then download the robot logs from the Opentrons App and send them to support@opentrons.com for assistance.", + "estop_pressed_description": "First, safely clear the deck of any labware or spills. Then, twist the E-stop button clockwise. Finally, have Flex move the gantry to its home position.", + "find_your_robot": "Find your robot in the Opentrons App to install software updates.", + "firmware_update_download_logs": "Download the robot logs from the Opentrons App and send them to support@opentrons.com for assistance.", + "general_error_message": "If you keep getting this message, try restarting your app and robot. If this does not resolve the issue, contact Opentrons Support.", + "gripper_still_attached": "Flex Gripper still attached", + "gripper_successfully_attached_and_calibrated": "Flex Gripper successfully attached and calibrated", + "gripper_successfully_calibrated": "Flex Gripper successfully calibrated", + "gripper_successfully_detached": "Flex Gripper successfully detached", + "gripper": "Flex Gripper", + "help_us_improve_send_error_report": "Help us improve your experience by sending an error report to {{support_email}}", + "ip_description_second": "Opentrons recommends working with your network administrator to assign a static IP address to the robot.", + "learn_uninstalling": "Learn more about uninstalling the Opentrons App", + "loosen_screws_and_detach": "Loosen screws and detach Flex Gripper", + "modal_instructions": "For step-by-step instructions on setting up your module, consult the Quickstart Guide that came in its box. You can also click the link below or scan the QR code to visit the modules section of the Opentrons Help Center.", + "module_calibration_failed": "Module calibration was unsuccessful. Make sure the calibration adapter is fully seated on the module and try again. If you still have trouble, contact Opentrons Support.{{error}}", + "module_calibration_get_started": "To get started, remove labware from the deck and clean up the working area to make the calibration easier. Also gather the needed equipment shown to the right.The calibration adapter came with your module. The pipette probe came with your Flex pipette.", + "module_error_contact_support": "Try powering the module off and on again. If the error persists, contact Opentrons Support.", + "network_setup_menu_description": "You’ll use this connection to run software updates and load protocols onto your Opentrons Flex.", + "oem_mode_description": "Enable OEM Mode to remove all instances of Opentrons from the Flex touchscreen.", + "opentrons_app_successfully_updated": "The Opentrons App was successfully updated.", + "opentrons_app_update": "Opentrons App update", + "opentrons_app_update_available": "Opentrons App Update Available", + "opentrons_app_update_available_variation": "An Opentrons App update is available.", + "opentrons_app_will_use_interpreter": "If specified, the Opentrons App will use the Python interpreter at this path instead of the default bundled Python interpreter.", + "opentrons_cares_about_privacy": "Opentrons cares about your privacy. We anonymize all data and only use it to improve our products.", + "opentrons_def": "Opentrons Definition", + "opentrons_labware_def": "Opentrons labware definition", + "opentrons_tip_rack_name": "opentrons", + "opentrons_tip_racks_recommended": "Opentrons tip racks are highly recommended. Accuracy cannot be guaranteed with other tip racks.", + "previous_releases": "View previous Opentrons releases", + "receive_alert": "Receive an alert when an Opentrons software update is available.", + "restore_description": "Opentrons does not recommend reverting to previous software versions, but you can access previous releases below. For best results, uninstall the existing app and remove its configuration files before installing the previous version.", + "robot_server_version_ot3_description": "The Opentrons Flex software includes the robot server and the touchscreen display interface.", + "robot_software_update_required": "A robot software update is required to run protocols with this version of the Opentrons App.", + "run_failed_modal_description_desktop": "Download the run log and send it to support@opentrons.com for assistance.", + "secure_labware_explanation_magnetic_module": "Opentrons recommends ensuring your labware locks to the Magnetic Module by adjusting the black plate bracket on top of the module. There are two sizes of plate brackets supplied with your module: standard and deep well. These brackets can be removed and swapped by unscrewing the module's thumb screw (the silver knob on the front).", + "secure_labware_explanation_thermocycler": "Opentrons recommends securing your labware to the Thermocycler Module by closing its latch. Doing so ensures level and accurate plate placement for optimal results.", + "send_a_protocol_to_store": "Send a protocol from the Opentrons App to get started.", + "setup_instructions_description": "For step-by-step instructions on setting up your module, consult the Quickstart Guide that came in its box or scan the QR code to visit the modules section of the Opentrons Help Center.", + "share_app_analytics": "Share App Analytics with Opentrons", + "share_app_analytics_description": "Help Opentrons improve its products and services by automatically sending anonymous diagnostics and usage data.", + "share_display_usage_description": "Data on how you interact with the touchscreen on Flex.", + "share_logs_with_opentrons": "Share Robot logs with Opentrons", + "share_logs_with_opentrons_description": "Help Opentrons improve its products and services by automatically sending anonymous robot logs. Opentrons uses these logs to troubleshoot robot issues and spot error trends.", + "show_labware_offset_snippets_description": "Only for users who need to apply labware offset data outside of the Opentrons App. When enabled, code snippets for Jupyter Notebook and SSH are available during protocol setup.", + "something_seems_wrong": "There may be a problem with your pipette. Exit setup and contact Opentrons Support for assistance.", + "these_are_advanced_settings": "These are advanced settings. Please do not attempt to adjust without assistance from Opentrons Support. Changing these settings may affect the lifespan of your pipette.These settings do not override any pipette settings defined in protocols.", + "update_requires_restarting_app": "Updating requires restarting the Opentrons App.", + "update_robot_software_description": "Bypass the Opentrons App auto-update process and update the robot software manually.", + "update_robot_software_link": "Launch Opentrons software update page", + "versions_sync": "Learn more about keeping the Opentrons App and robot software in sync", + "view_latest_release_notes_at": "View latest release notes at {{url}}", + "want_to_help_out": "Want to help out Opentrons?", + "welcome_title": "Welcome to your Opentrons Flex!", + "why_use_lpc": "Labware Position Check is intended to correct for minor variances. Opentrons does not recommend using Labware Position Check to compensate for large positional adjustments. Needing to set large labware offsets could indicate a problem with robot calibration." +} diff --git a/app/src/assets/localization/en/device_details.json b/app/src/assets/localization/en/device_details.json index d217718af42..d3fdab0b04c 100644 --- a/app/src/assets/localization/en/device_details.json +++ b/app/src/assets/localization/en/device_details.json @@ -1,11 +1,10 @@ { - "about_flex_gripper": "About Flex Gripper", "about_gripper": "About gripper", "about_module": "About {{name}}", "about_pipette_name": "About {{name}} Pipette", "about_pipette": "About pipette", - "add_fixture_description": "Add this fixture to your deck configuration. It will be referenced during protocol analysis.", - "add_to_slot_description": "Choose a fixture below to add to your deck configuration. It will be referenced during protocol analysis.", + "add_fixture_description": "Add this item to your deck configuration. It will be referenced during protocol analysis.", + "add_to_slot_description": "Choose an item below to add to your deck configuration. It will be referenced during protocol analysis.", "add_to_slot": "Add to slot {{slotName}}", "add": "Add", "an_error_occurred_while_updating_module": "An error occurred while updating your {{moduleName}}. Please try again.", @@ -40,8 +39,8 @@ "deck_configuration": "deck configuration", "deck_fixture_setup_instructions": "Deck fixture setup instructions", "deck_fixture_setup_modal_bottom_description_desktop": "For detailed instructions for different types of fixtures, scan the QR code or go to the link below.", - "deck_fixture_setup_modal_bottom_description": "For details on installing different fixture types, scan the QR code or search for “deck configuration” on support.opentrons.com", "deck_fixture_setup_modal_top_description": "First, unscrew and remove the deck slot where you'll install a fixture. Then put the fixture in place and attach it as needed.", + "deck_hardware": "deck hardware", "deck_slot": "deck slot {{slot}}", "delete_run": "Delete protocol run record", "detach_gripper": "Detach gripper", @@ -59,7 +58,7 @@ "firmware_update_needed": "Instrument firmware update needed. Start the update on the robot's touchscreen.", "firmware_update_available": "Firmware update available.", "firmware_update_failed": "Failed to update module firmware", - "firmware_update_installation_successful": "Installation successful", + "firmware_updated_successfully": "Firmware updated successfully", "firmware_update_occurring": "Firmware update in progress...", "fixture": "Fixture", "have_not_run_description": "After you run some protocols, they will appear here.", @@ -94,7 +93,6 @@ "module_calibration_required_update_pipette_FW": "Update pipette firmware before proceeding with required module calibration.", "module_calibration_required": "Module calibration required.", "module_controls": "Module Controls", - "module_error_contact_support": "Try powering the module off and on again. If the error persists, contact Opentrons Support.", "module_error": "Module error", "module_name_error": "{{moduleName}} error", "module_status_range": "Between {{min}} - {{max}} {{unit}}", @@ -177,7 +175,6 @@ "tempdeck_slideout_body": "Pre heat or cool your {{model}}. Enter a whole number between 4 °C and 96 °C.", "tempdeck_slideout_title": "Set Temperature for {{name}}", "temperature": "Temperature", - "these_are_advanced_settings": "These are advanced settings. Please do not attempt to adjust without assistance from Opentrons Support. Changing these settings may affect the lifespan of your pipette.These settings do not override any pipette settings defined in protocols.", "this_robot_will_restart_with_update": "This robot has to restart to update its software. Restarting will immediately stop the current run or calibration.Do you want to update now anyway?", "tip_pickup_drop": "Tip Pickup / Drop", "to_run_protocol_go_to_protocols_page": "To run a protocol on this robot, import a protocol on the Protocols page", diff --git a/app/src/assets/localization/en/device_settings.json b/app/src/assets/localization/en/device_settings.json index f92a6e30d69..78d23493234 100644 --- a/app/src/assets/localization/en/device_settings.json +++ b/app/src/assets/localization/en/device_settings.json @@ -6,7 +6,6 @@ "advanced": "Advanced", "alpha_description": "Warning: alpha releases are feature-complete but may contain significant bugs.", "alternative_security_types": "Alternative security types", - "alternative_security_types_description": "The Opentrons App supports connecting Flex to various enterprise access points. Connect via USB and finish setup in the app.", "app_change_in": "App Changes in {{version}}", "apply_historic_offsets": "Apply Labware Offsets", "are_you_sure_you_want_to_disconnect": "Are you sure you want to disconnect from {{ssid}}?", @@ -30,6 +29,7 @@ "check_for_updates": "Check for updates", "checking_for_updates": "Checking for updates", "choose": "Choose...", + "choose_file": "Choose file", "choose_network_type": "Choose network type", "choose_reset_settings": "Choose reset settings", "clear_all_data": "Clear all data", @@ -51,6 +51,7 @@ "clear_option_runs_history_subtext": "Clears information about past runs of all protocols.", "clear_option_tip_length_calibrations": "Clear tip length calibrations", "cancel_software_update": "Cancel software update", + "complete_and_restart_robot": "Complete and restart robot", "confirm_device_reset_description": "This will permanently delete all protocol, calibration, and other data. You’ll have to redo initial setup before using the robot again.", "confirm_device_reset_heading": "Are you sure you want to reset your device?", "connect": "Connect", @@ -59,16 +60,13 @@ "connect_via": "Connect via {{type}}", "connect_via_usb_description_1": "1. Connect the USB A-to-B cable to the robot’s USB-B port.", "connect_via_usb_description_2": "2. Connect the cable to an open USB port on your computer.", - "connect_via_usb_description_3": "3. Launch the Opentrons App on the computer to continue.", "connected": "Connected", "connected_network": "Connected Network", "connected_to_ssid": "Connected to {{ssid}}", "connected_via": "Connected via {{networkInterface}}", "connecting_to": "Connecting to {{ssid}}...", "connection_description_ethernet": "Connect to your lab's wired network.", - "connection_description_usb": "Connect directly to a computer (running the Opentrons App).", "connection_description_wifi": "Find a network in your lab or enter your own.", - "connection_lost_description": "The Opentrons App is unable to communicate with this robot right now. Double check the USB or Wifi connection to the robot, then try to reconnect.", "connection_to_robot_lost": "Connection to robot lost", "deck_calibration_description": "Calibrating the deck is required for new robots or after you relocate your robot. Recalibrating the deck will require you to also recalibrate pipette offsets.", "deck_calibration_missing": "Deck calibration missing", @@ -111,6 +109,7 @@ "enable_status_light": "Enable status light", "enable_status_light_description": "Turn on or off the strip of color LEDs on the front of the robot.", "engaged": "Engaged", + "enter_factory_password": "Enter factory password", "enter_network_name": "Enter network name", "enter_password": "Enter password", "estop": "E-stop", @@ -119,17 +118,16 @@ "estop_missing": "E-stop missing", "estop_missing_description": "Your E-stop could be damaged or detached. {{robotName}} lost its connection to the E-stop, so it canceled the protocol. Connect a functioning E-stop to continue.", "estop_pressed": "E-stop pressed", - "estop_pressed_description": "First, safely clear the deck of any labware or spills. Then, twist the E-stop button clockwise. Finally, have Flex move the gantry to its home position.", "ethernet": "Ethernet", "ethernet_connection_description": "Connect an Ethernet cable to the back of the robot and a network switch or hub.", "exit": "exit", + "factory_mode": "Factory Mode", "factory_reset": "Factory Reset", "factory_reset_description": "Resets all settings. You’ll have to redo initial setup before using the robot again.", "factory_reset_modal_description": "This data cannot be retrieved later.", "factory_resets_cannot_be_undone": "Factory resets cannot be undone.", "failed_to_connect_to_ssid": "Failed to connect to {{ssid}}", "feature_flags": "Feature Flags", - "find_your_robot": "Find your robot in the Opentrons App to install software updates.", "finish_setup": "Finish setup", "firmware_version": "Firmware Version", "fully_calibrate_before_checking_health": "Fully calibrate your robot before checking calibration health", @@ -146,6 +144,7 @@ "install_e_stop": "Install the E-stop", "installing_software": "Installing software...", "installing_update": "Installing update...", + "invalid_password": "Invalid password", "ip_address": "IP Address", "join_other_network": "Join other network", "join_other_network_error_message": "Must be 2–32 characters long", @@ -157,6 +156,7 @@ "launch_jupyter_notebook": "Launch Jupyter Notebook", "legacy_settings": "Legacy Settings", "mac_address": "MAC Address", + "manage_oem_settings": "Manage OEM settings", "minutes": "{{minute}} minutes", "missing_calibration": "Missing calibration", "model_and_serial": "Pipette Model and Serial", @@ -174,7 +174,6 @@ "need_another_security_type": "Need another security type?", "network_name": "Network Name", "network_settings": "Network Settings", - "network_setup_menu_description": "You’ll use this connection to run software updates and load protocols onto your Opentrons Flex.", "networking": "Networking", "never": "Never", "new_features": "New Features", @@ -193,7 +192,10 @@ "not_connected_via_wifi": "Not connected via Wi-Fi", "not_connected_via_wired_usb": "Not connected via wired USB", "not_now": "Not now", + "oem_mode": "OEM Mode", + "off": "Off", "one_hour": "1 hour", + "on": "On", "other_networks": "Other Networks", "password": "Password", "password_error_message": "Must be at least 8 characters", @@ -240,10 +242,8 @@ "robot_operating_update_available": "Robot Operating System Update Available", "robot_serial_number": "Robot Serial Number", "robot_server_version": "Robot Server Version", - "robot_server_version_ot3_description": "The Opentrons Flex software includes the robot server and the touchscreen display interface.", "robot_settings": "Robot Settings", "robot_settings_advanced_unknown": "Unknown", - "robot_software_update_required": "A robot software update is required to run protocols with this version of the Opentrons App.", "robot_successfully_connected": "Robot successfully connected to {{networkName}}.", "robot_system_version": "Robot System Version", "robot_system_version_available": "Robot System Version {{releaseVersion}} available", @@ -261,10 +261,7 @@ "select_authentication_method": "Select authentication method for your selected network.", "sending_software": "Sending software...", "serial": "Serial", - "share_logs_with_opentrons": "Share Robot logs with Opentrons", - "share_logs_with_opentrons_description": "Help Opentrons improve its products and services by automatically sending anonymous robot logs. Opentrons uses these logs to troubleshoot robot issues and spot error trends.", - "share_logs_with_opentrons_description_short": "Share anonymous robot logs with Opentrons.", - "share_logs_with_opentrons_short": "Share Robot logs", + "setup_mode": "Setup mode", "short_trash_bin": "Short trash bin", "short_trash_bin_description": "For pre-2019 robots with trash bins that are 55mm tall (instead of 77mm default)", "show": "Show", @@ -278,7 +275,6 @@ "successfully_connected": "Successfully connected!", "successfully_connected_to_network": "Successfully connected to {{ssid}}!", "supported_protocol_api_versions": "Supported Protocol API Versions", - "switch_to_usb_description": "If your network uses a different authentication method, connect to the Opentrons App and finish Wi-Fi setup there.", "text_size": "Text Size", "text_size_description": "Text on all screens will adjust to the size you choose below.", "tip_length_calibrations_history": "See all Tip Length Calibration history", @@ -296,27 +292,21 @@ "update_found": "Update found!", "update_robot_now": "Update robot now", "update_robot_software": "Update robot software manually with a local file (.zip)", - "update_robot_software_description": "Bypass the Opentrons App auto-update process and update the robot software manually.", - "update_robot_software_link": "Launch Opentrons software update page", "updating": "Updating", - "update_requires_restarting": "Updating the robot software requires restarting the robot", + "update_requires_restarting_robot": "Updating the robot software requires restarting the robot", + "upload_custom_logo_description": "Upload a logo for the robot to display during boot up. If no file is uploaded, we will display an anonymous logo.", + "upload_custom_logo_dimensions": "The logo must fit within dimensions 1024 x 600 and be a PNG file (.png).", + "upload_custom_logo": "Upload custom logo", "usage_settings": "Usage Settings", "usb": "USB", "usb_to_ethernet_description": "Looking for USB-to-Ethernet Adapter info?", "use_older_aspirate": "Use older aspirate behavior", "use_older_aspirate_description": "Aspirate with the less accurate volumetric calibrations that were used before version 3.7.0. Use this if you need consistency with pre-v3.7.0 results. This only affects GEN1 P10S, P10M, P50M, and P300S pipettes.", - "use_older_protocol_analysis_method": "Use older protocol analysis method", - "use_older_protocol_analysis_method_description": "Use an older, slower method of analyzing uploaded protocols. This changes how the OT-2 validates your protocol during the upload step, but does not affect how your protocol actually runs. Opentrons Support might ask you to change this setting if you encounter problems with the newer, faster protocol analysis method.", "validating_software": "Validating software...", "view_details": "View details", - "view_latest_release_notes_at": "View latest release notes at {{url}}", "view_network_details": "View network details", - "view_opentrons_issue_tracker": "View Opentrons issue tracker", - "view_opentrons_release_notes": "View full Opentrons release notes", - "view_opentrons_technical_change_log": "View Opentrons technical change log", "view_update": "View update", "welcome_description": "Quickly run protocols and check on your robot's status right on your lab bench.", - "welcome_title": "Welcome to your Opentrons Flex!", "wifi": "Wi-Fi", "wired_ip": "Wired IP", "wired_mac_address": "Wired MAC Address", diff --git a/app/src/assets/localization/en/devices_landing.json b/app/src/assets/localization/en/devices_landing.json index 60a25974fec..b0a3307ace1 100644 --- a/app/src/assets/localization/en/devices_landing.json +++ b/app/src/assets/localization/en/devices_landing.json @@ -4,7 +4,6 @@ "check_same_network": "Check that the computer and robot are on the same network", "connect_to_network": "Connect to network", "connection_troubleshooting_intro": "If you’re having trouble with the robot’s connection, try these troubleshooting tasks. First, double check that the robot is powered on.", - "contact_support_for_connection_help": "If none of these work, contact Opentrons Support for help (via the question mark link in this app, or by emailing {{support_email}}.)", "deck_configuration": "Deck configuration", "devices": "Devices", "disconnect_from_network": "Disconnect from network", diff --git a/app/src/assets/localization/en/drop_tip_wizard.json b/app/src/assets/localization/en/drop_tip_wizard.json index 66924d00210..fc3bf25dfdf 100644 --- a/app/src/assets/localization/en/drop_tip_wizard.json +++ b/app/src/assets/localization/en/drop_tip_wizard.json @@ -3,10 +3,12 @@ "begin_removal": "Begin removal", "blowout_complete": "blowout complete", "blowout_liquid": "Blow out liquid", + "cant_safely_drop_tips": "Can't safely drop tips", "choose_blowout_location": "choose blowout location", "choose_drop_tip_location": "choose tip-drop location", "confirm_blowout_location": "Is the pipette positioned where the liquids should be blown out?", "confirm_drop_tip_location": "Is the pipette positioned where the tips should be dropped?", + "confirm_removal_and_home": "Confirm removal and home", "drop_tip_complete": "tip drop complete", "drop_tip_failed": "The drop tip could not be completed. Contact customer support for assistance.", "drop_tips": "drop tips", @@ -21,6 +23,7 @@ "position_the_pipette": "position the pipette", "remove_the_tips": "You may want to remove the tips from the {{mount}} Pipette before using it again in a protocol.", "remove_the_tips_from_pipette": "You may want to remove the tips from the pipette before using it again in a protocol.", + "remove_the_tips_manually": "Remove the tips manually. Then home the gantry. Homing with tips attached could pull liquid into the pipette and damage it.", "remove_tips": "Remove tips", "select_blowout_slot": "You can blow out liquid into a labware or dispose of it.Select the slot where you want to blow out the liquid on the deck map to the right. Once confirmed, the gantry will move to the chosen slot.", "select_blowout_slot_odd": "You can blow out liquid into a labware or dispose of it.
After the gantry moves to the chosen slot, use the jog controls to move the pipette to the exact position for blowing out.", diff --git a/app/src/assets/localization/en/error_recovery.json b/app/src/assets/localization/en/error_recovery.json new file mode 100644 index 00000000000..f606e5fdf33 --- /dev/null +++ b/app/src/assets/localization/en/error_recovery.json @@ -0,0 +1,19 @@ +{ + "are_you_sure_you_want_to_resume": "Are you sure you want to resume?", + "before_you_begin": "Before you begin", + "cancel_run": "Cancel run", + "confirm": "Confirm", + "continue": "Continue", + "general_error": "General error", + "general_error_message": "", + "go_back": "Go back", + "how_do_you_want_to_proceed": "How do you want to proceed?", + "recovery_mode": "Recovery Mode", + "recovery_mode_explanation": "Recovery Mode provides you with guided and manual controls for handling errors at runtime.
You can make changes to ensure the step in progress when the error occurred can be completed or choose to cancel the protocol. When changes are made and no subsequent errors are detected, the method completes. Depending on the conditions that caused the error, you will only be provided with appropriate options.", + "resume": "Resume", + "run_paused": "Run paused", + "run_will_resume": "The run will resume from the point at which the error occurred. Take any necessary actions to correct the problem first. If the step is completed successfully, the protocol continues.", + "stand_back": "Stand back, robot is in motion", + "stand_back_resuming": "Stand back, resuming current step", + "view_recovery_options": "View recovery options" +} diff --git a/app/src/assets/localization/en/firmware_update.json b/app/src/assets/localization/en/firmware_update.json index 8abe122d914..5d543032e12 100644 --- a/app/src/assets/localization/en/firmware_update.json +++ b/app/src/assets/localization/en/firmware_update.json @@ -1,10 +1,10 @@ { - "download_logs": "Download the robot logs from the Opentrons App and send them to support@opentrons.com for assistance.", "firmware_out_of_date": "The firmware for {{mount}} {{instrument}} is out of date. You need to update it before running protocols that use this instrument.", "gantry_x": "Gantry X", "gantry_y": "Gantry Y", "gripper": "Gripper", "head": "Head", + "hepa_uv": "HEPA/UV Module", "pipette_left": "pipette", "pipette_right": "pipette", "ready_to_use": "Your {{instrument}} is ready to use!", diff --git a/app/src/assets/localization/en/gripper_wizard_flows.json b/app/src/assets/localization/en/gripper_wizard_flows.json index a868cdb474e..ff98d8e07f0 100644 --- a/app/src/assets/localization/en/gripper_wizard_flows.json +++ b/app/src/assets/localization/en/gripper_wizard_flows.json @@ -8,7 +8,6 @@ "calibration_pin": "Calibration Pin", "calibration_pin_touching": "The calibration pin will touch the calibration square in slot {{slot}} to determine its exact position.", "complete_calibration": "Complete calibration", - "connect_and_screw_in_gripper": "Connect and secure Flex Gripper", "continue": "Continue", "continue_calibration": "Continue calibration", "detach_gripper": "Detach Gripper", @@ -17,17 +16,11 @@ "get_started": "Get started", "gripper_calibration": "Gripper Calibration", "gripper_recalibration": "Gripper Recalibration", - "gripper_still_attached": "Flex Gripper still attached", - "gripper_successfully_attached_and_calibrated": "Flex Gripper successfully attached and calibrated", "gripper_successfully_attached": "Gripper successfully attached", - "gripper_successfully_calibrated": "Flex Gripper successfully calibrated", - "gripper_successfully_detached": "Flex Gripper successfully detached", - "gripper": "Flex Gripper", "hex_screwdriver": "2.5 mm Hex Screwdriver", "hold_gripper_and_loosen_screws": "Hold the gripper in place and loosen the top gripper screw first. After that move onto the bottom screw. (The screws are captive and will not come apart from the gripper.) Then carefully remove the gripper.", "insert_pin_into_front_jaw": "Insert calibration pin in front jaw", "insert_pin_into_rear_jaw": "Insert calibration pin in rear jaw", - "loosen_screws_and_detach": "Loosen screws and detach Flex Gripper", "move_gantry_to_front": "Move gantry to front", "move_pin_from_front_to_rear_jaw": "Remove the calibration pin from the front jaw and attach it to the rear jaw.", "move_pin_from_rear_jaw_to_storage": "Take the calibration pin from the rear gripper jaw and return it to its storage location.", diff --git a/app/src/assets/localization/en/index.ts b/app/src/assets/localization/en/index.ts index c7256b1d415..51acf92db53 100644 --- a/app/src/assets/localization/en/index.ts +++ b/app/src/assets/localization/en/index.ts @@ -1,5 +1,7 @@ import shared from './shared.json' +import anonymous from './anonymous.json' import app_settings from './app_settings.json' +import branded from './branded.json' import change_pipette from './change_pipette.json' import protocol_command_text from './protocol_command_text.json' import device_details from './device_details.json' @@ -14,25 +16,23 @@ import labware_details from './labware_details.json' import labware_landing from './labware_landing.json' import labware_position_check from './labware_position_check.json' import module_wizard_flows from './module_wizard_flows.json' -import more_network_and_system from './more_network_and_system.json' -import more_panel from './more_panel.json' import pipette_wizard_flows from './pipette_wizard_flows.json' -import protocol_calibration from './protocol_calibration.json' import protocol_details from './protocol_details.json' import protocol_info from './protocol_info.json' import protocol_list from './protocol_list.json' import protocol_setup from './protocol_setup.json' -import robot_advanced_settings from './robot_advanced_settings.json' +import quick_transfer from './quick_transfer.json' import robot_calibration from './robot_calibration.json' -import robot_connection from './robot_connection.json' import robot_controls from './robot_controls.json' -import robot_info from './robot_info.json' import run_details from './run_details.json' import top_navigation from './top_navigation.json' +import error_recovery from './error_recovery.json' export const en = { shared, + anonymous, app_settings, + branded, change_pipette, protocol_command_text, device_details, @@ -47,19 +47,15 @@ export const en = { labware_landing, labware_position_check, module_wizard_flows, - more_network_and_system, - more_panel, pipette_wizard_flows, - protocol_calibration, protocol_details, protocol_info, protocol_list, protocol_setup, - robot_advanced_settings, + quick_transfer, robot_calibration, - robot_connection, robot_controls, - robot_info, run_details, top_navigation, + error_recovery, } diff --git a/app/src/assets/localization/en/labware_landing.json b/app/src/assets/localization/en/labware_landing.json index 63212567561..17eebda979d 100644 --- a/app/src/assets/localization/en/labware_landing.json +++ b/app/src/assets/localization/en/labware_landing.json @@ -22,8 +22,6 @@ "labware": "labware", "last_updated": "Last updated", "open_labware_creator": "Open Labware Creator", - "opentrons_def": "Opentrons Definition", - "opentrons_labware_def": "Opentrons labware definition", "show_in_folder": "Show in folder", "unable_to_upload": "Unable to upload file", "yes_delete_def": "Yes, delete definition" diff --git a/app/src/assets/localization/en/labware_position_check.json b/app/src/assets/localization/en/labware_position_check.json index f08c465f7fa..4072826650a 100644 --- a/app/src/assets/localization/en/labware_position_check.json +++ b/app/src/assets/localization/en/labware_position_check.json @@ -27,9 +27,6 @@ "detach_probe": "Remove calibration probe", "ensure_nozzle_position_odd": "Ensure that the {{tip_type}} is centered above and level with {{item_location}}. If it isn't, tap Move pipette and then jog the pipette until it is properly aligned.", "ensure_nozzle_position_desktop": "Ensure that the {{tip_type}} is centered above and level with {{item_location}}. If it isn't, use the controls below or your keyboard to jog the pipette until it is properly aligned.", - "error_modal_header": "Something went wrong", - "error_modal_problem_in_app": "There was an error performing Labware Position Check. Please restart the app. If the problem persists, please contact Opentrons Support", - "error_modal_problem_on_robot": "There was an error processing your request on the robot", "exit_screen_confirm_exit": "Exit and discard all labware offsets", "exit_screen_go_back": "Go back to labware position check", "exit_screen_subtitle": "If you exit now, all labware offsets will be discarded. This cannot be undone.", diff --git a/app/src/assets/localization/en/module_wizard_flows.json b/app/src/assets/localization/en/module_wizard_flows.json index 636bb368662..a502b0ef797 100644 --- a/app/src/assets/localization/en/module_wizard_flows.json +++ b/app/src/assets/localization/en/module_wizard_flows.json @@ -21,12 +21,10 @@ "exit": "Exit", "firmware_up_to_date": "{{module}} firmware up to date.", "firmware_updated": "{{module}} firmware updated!", - "get_started": "To get started, remove labware from the deck and clean up the working area to make the calibration easier. Also gather the needed equipment shown to the right.The calibration adapter came with your module. The pipette probe came with your Flex pipette.", "install_adapter": "Place calibration adapter in {{module}}", "install_calibration_adapter": "Install calibration adapter", "location_occupied": "A {{fixture}} is currently specified here on the deck configuration", "module_calibrating": "Stand back, {{moduleName}} is calibrating", - "module_calibration_failed": "Module calibration was unsuccessful. Make sure the calibration adapter is fully seated on the module and try again. If you still have trouble, contact Opentrons Support.{{error}}", "module_calibration": "Module calibration", "module_secured": "The module must be fully secured in its caddy and secured in the deck slot.", "module_too_hot": "Module is too hot to proceed to module calibration", diff --git a/app/src/assets/localization/en/more_network_and_system.json b/app/src/assets/localization/en/more_network_and_system.json deleted file mode 100644 index a6fd1593b38..00000000000 --- a/app/src/assets/localization/en/more_network_and_system.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "description": "Description", - "driver_version": "Driver Version", - "launch_realtek_adapter_drivers_site": "Launch Realtek Adapter Drivers Site", - "manufacturer": "Manufacturer", - "network_and_system_title": "Network & System", - "u2e_adapter_information": "USB-to-Ethernet Adapter Information", - "u2e_driver_update_alert": "Update available for Realtek USB-to-Ethernet adapter driver" -} diff --git a/app/src/assets/localization/en/more_panel.json b/app/src/assets/localization/en/more_panel.json deleted file mode 100644 index 63b594c1f37..00000000000 --- a/app/src/assets/localization/en/more_panel.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "app": "App", - "custom_labware": "Custom Labware", - "network_and_system": "Network & System", - "resources": "Resources" -} diff --git a/app/src/assets/localization/en/pipette_wizard_flows.json b/app/src/assets/localization/en/pipette_wizard_flows.json index 5d13142349c..53ae23d07e2 100644 --- a/app/src/assets/localization/en/pipette_wizard_flows.json +++ b/app/src/assets/localization/en/pipette_wizard_flows.json @@ -32,7 +32,7 @@ "detach_mount_attach_96": "Detach {{mount}} Pipette and Attach 96-Channel Pipette", "detach_mounting_plate_instructions": "Hold onto the plate so it does not fall. Then remove the pins on the plate from the slots on the gantry carriage.", "detach_next_pipette": "Detach next pipette", - "detach_pipette_to_attach_96": "Detach {{pipetteName}} and attach 96-Channel pipette", + "detach_pipette_to_attach_96": "Detach {{pipetteName}} and Attach 96-Channel pipette", "detach_pipette": "detach {{mount}} pipette", "detach_pipettes_attach_96": "Detach Pipettes and Attach 96-Channel Pipette", "detach_z_axis_screw_again": "detach the z-axis screw before attaching the 96-Channel Pipette.", @@ -77,7 +77,6 @@ "return_probe_error": "Return the calibration probe to its storage location before exiting. {{error}}", "single_mount_attached_error": "Single mount pipette is selected when this is the 96 channel flow", "single_or_8_channel": "{{single}} or {{eight}} pipette", - "something_seems_wrong": "There may be a problem with your pipette. Exit setup and contact Opentrons Support for assistance.", "stand_back": "Stand back, robot is in motion", "try_again": "try again", "unable_to_detect_probe": "Unable to detect calibration probe", diff --git a/app/src/assets/localization/en/protocol_calibration.json b/app/src/assets/localization/en/protocol_calibration.json deleted file mode 100644 index 1c65b64721f..00000000000 --- a/app/src/assets/localization/en/protocol_calibration.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "cal_data_existing_data": "Existing data", - "cal_data_legacy_definition": "Calibration Data N/A", - "cal_data_not_calibrated": "Not yet calibrated", - "cal_data_updated_data": "Updated data", - "cal_panel_title": "Placement and Calibration", - "labware_cal_labware_title": "labware", - "labware_cal_tipracks_title": "tip racks", - "labware_cal_title": "Labware Calibration", - "module_connect_description": "Power up and plug in the required module(s) via the OT-2 USB Ports. Place the modules as shown in the deck map.", - "module_connect_duplicate_description": "Plug the modules in to the USB ports as listed in the Placement and Calibration Panel. Check out our help docs for more information on using modules of the same type.", - "module_connect_instruction": "Plug the modules in to the USB ports as listed below, from left to right.", - "module_connect_missing_tooltip": "Connect module(s) to proceed to labware calibration", - "module_connect_proceed_button": "Continue to labware setup", - "modules_deck_slot_title": "slot", - "modules_module_title": "module", - "modules_title": "modules", - "modules_update_software_tooltip": "Update robot software to see USB port information", - "modules_usb_order_title": "USB order (L to R)", - "modules_usb_port_title": "USB port", - "tip_length_cal_title": "Tip Length Calibration" -} diff --git a/app/src/assets/localization/en/protocol_info.json b/app/src/assets/localization/en/protocol_info.json index d1e73288dcd..20d618db601 100644 --- a/app/src/assets/localization/en/protocol_info.json +++ b/app/src/assets/localization/en/protocol_info.json @@ -10,7 +10,6 @@ "creation_method": "Creation Method", "custom_labware_not_supported": "Robot doesn't support custom labware", "date_added": "Date Added", - "delete_protocol_from_app": "Delete the protocol, make changes to address the error, and resend the protocol to this robot from the Opentrons App.", "delete_protocol": "Delete protocol", "description": "Description", "drag_file_here": "Drag and drop protocol file here", @@ -69,16 +68,11 @@ "required_cal_data_title": "Calibration Data", "required_quantity_title": "Quantity", "required_type_title": "Type", - "rerunning_protocol_modal_body": "Opentrons displays the connected robot’s last protocol run on on the Protocol Upload page. If you run again, Opentrons loads this protocol and applies Labware Offset data if any exists.Clicking “Run Again” will take you directly to the Run tab. If you’d like to review the deck setup or run Labware Position Check before running the protocol, navigate to the Protocol tab.If you recalibrate your robot, it will clear the last run from the upload page. A run can have the following statuses:Not started: when this protocol was loaded on to the robot, it was closed before the user ran itCanceled: when this protocol was loaded on to the robot, it was canceled before the run completedComplete: when this protocol was loaded on to the robot, it was closed after the protocol run completed", - "rerunning_protocol_modal_header": "How Rerunning A Protocol Works", - "rerunning_protocol_modal_link": "Learn more about Labware Offset Data", - "rerunning_protocol_modal_title": "See How Rerunning a Protocol Works", "robot_name_last_run": "{{robot_name}}’s last run", "robot_type_first": "{{robotType}} protocols first", "run_again": "Run again", "run_protocol": "Run protocol", "run_timestamp_title": "Run timestamp", - "send_a_protocol_to_store": "Send a protocol from the Opentrons App to get started.", "simulation_in_progress": "Simulation in Progress", "timestamp": "+{{index}}", "too_many_pins_body": "Remove a protocol in order to add more protocols to your pinned list.", diff --git a/app/src/assets/localization/en/protocol_list.json b/app/src/assets/localization/en/protocol_list.json index d014c27abae..76c1b068d94 100644 --- a/app/src/assets/localization/en/protocol_list.json +++ b/app/src/assets/localization/en/protocol_list.json @@ -1,5 +1,4 @@ { - "a_robot_software_update_is_available": "A robot software update is required to run protocols with this version of the Opentrons App. Go to Robot", "delete_protocol_message": " and its run history will be permanently deleted.", "last_updated_at": "Updated {{date}}", "left_mount": "left mount", diff --git a/app/src/assets/localization/en/protocol_setup.json b/app/src/assets/localization/en/protocol_setup.json index 99b496a3479..9406bbe16f5 100644 --- a/app/src/assets/localization/en/protocol_setup.json +++ b/app/src/assets/localization/en/protocol_setup.json @@ -3,10 +3,11 @@ "action_needed": "Action needed", "adapter_slot_location_module": "Slot {{slotName}}, {{adapterName}} on {{moduleName}}", "adapter_slot_location": "Slot {{slotName}}, {{adapterName}}", - "add_fixture_to_deck": "Add this fixture to your deck configuration. It will be referenced during protocol analysis.", "add_fixture": "Add {{fixtureName}} to deck configuration", "additional_labware": "{{count}} additional labware", "additional_off_deck_labware": "Additional Off-Deck Labware", + "add_this_deck_hardware": "Add this deck hardware to your deck configuration. It will be referenced during protocol analysis.", + "add_to_slot": "Add to slot {{slotName}}", "attach_gripper_failure_reason": "Attach the required gripper to continue", "attach_gripper": "attach gripper", "attach_module": "Attach module before calibrating", @@ -38,6 +39,7 @@ "calibration_status": "calibration status", "calibration": "Calibration", "cancel_and_restart_to_edit": "Cancel the run and restart setup to edit", + "exit_to_deck_configuration": "Exit to deck configuration", "choose_enum": "Choose {{displayName}}", "closing": "Closing...", "complete_setup_before_proceeding": "complete setup before continuing run", @@ -48,6 +50,7 @@ "confirm_values": "Confirm values", "connect_all_hardware": "Connect and calibrate all hardware first", "connect_all_mod": "Connect all modules first", + "connect_modules_for_controls": "Connect modules to see controls", "connection_info_not_available": "Connection info not available once run has started", "connection_status": "Connection Status", "currently_configured": "Currently configured", @@ -60,6 +63,7 @@ "deck_conflict_info_thermocycler": "Update the deck configuration by removing the fixtures in locations A1 and B1. Either remove the fixtures from the deck configuration or update the protocol.", "deck_conflict_info": "Update the deck configuration by removing the {{currentFixture}} in location {{cutout}}. Either remove the fixture from the deck configuration or update the protocol.", "deck_conflict": "Deck location conflict", + "deck_hardware": "Deck hardware", "deck_map": "Deck Map", "default_values": "Default values", "example": "Example", @@ -121,8 +125,6 @@ "lpc_disabled_modules_not_connected": "Make sure all modules are connected before running Labware Position Check", "lpc_disabled_no_tipracks_loaded": "Labware Position Check requires that the protocol loads a tip rack", "lpc_disabled_no_tipracks_used": "Labware Position Check requires that the protocol has at least one pipette that picks up a tip", - "magnetic_module_attention_warning": "Opentrons recommends securing labware with the module’s bracket. See how to secure labware to the Magnetic Module", - "magnetic_module_extra_attention": "Opentrons recommends securing labware with the module’s bracket", "map_view": "Map View", "missing_gripper": "Missing gripper", "missing_instruments": "Missing {{count}}", @@ -130,7 +132,6 @@ "missing_pipettes": "Missing {{count}} pipette", "missing": "Missing", "modal_instructions_title": "{{moduleName}} Setup Instructions", - "modal_instructions": "For step-by-step instructions on setting up your module, consult the Quickstart Guide that came in its box. You can also click the link below or scan the QR code to visit the modules section of the Opentrons Help Center.", "module_and_deck_setup": "Modules & deck", "module_connected": "Connected", "module_disconnected": "Disconnected", @@ -143,7 +144,6 @@ "module_setup_step_title": "Modules", "module_slot_location": "Slot {{slotName}}, {{moduleName}}", "module": "Module", - "modules_and_deck": "Modules & deck", "modules_connected_plural": "{{count}} modules attached", "modules_connected": "{{count}} module attached", "modules_setup_step_title": "Module Setup", @@ -197,6 +197,7 @@ "pipette_offset_cal_description": "This measures a pipette’s X, Y and Z values in relation to the pipette mount and the deck. Pipette Offset Calibration relies on Deck Calibration and Tip Length Calibration. ", "pipette_offset_cal": "Pipette Offset Calibration", "placement": "Placement", + "plug_in_module_to_configure": "Plug in a {{module}} to add it to the slot", "plug_in_required_module_plural": "Plug in and power up the required modules to continue", "plug_in_required_module": "Plug in and power up the required module to continue", "prepare_to_run": "Prepare to run", @@ -227,7 +228,8 @@ "resolve": "Resolve", "restart_setup_and_try": "Restart setup and try using different parameter values.", "restart_setup": "Restart setup", - "restore_default": "Restore default values", + "restore_defaults": "Restore default values", + "restore_default": "Restore default value", "robot_cal_description": "Robot calibration establishes how the robot knows where it is in relation to the deck. Accurate Robot calibration is essential to run protocols successfully. Robot calibration has 3 parts: Deck calibration, Tip Length calibration and Pipette Offset calibration.", "robot_cal_help_title": "How Robot Calibration Works", "robot_calibration_step_description_pipettes_only": "Review required instruments and calibrations for this protocol.", @@ -237,39 +239,38 @@ "run_disabled_modules_and_calibration_not_complete": "Make sure robot calibration is complete and all modules are connected before proceeding to run", "run_disabled_modules_not_connected": "Make sure all modules are connected before proceeding to run", "run_labware_position_check": "run labware position check", + "run_never_started": "Run was never started", "run": "Run", - "secure_labware_explanation_magnetic_module": "Opentrons recommends ensuring your labware locks to the Magnetic Module by adjusting the black plate bracket on top of the module. Please note there are two sizes of plate brackets supplied with your module: standard and deep well. These brackets can be removed and swapped by unscrewing the modules thumb screw (the silver knob on the front).", - "secure_labware_explanation_thermocycler": "Opentrons recommends securing your labware to the Thermocycler module by closing its latch. Doing so ensures level and accurate plate placement for optimal results.", "secure_labware_instructions": "Secure labware instructions", "secure_labware_modal": "Securing labware to the {{name}}", "secure": "Secure", "setup_for_run": "Setup for Run", - "setup_instructions_description": "For step-by-step instructions on setting up your module, consult the Quickstart Guide that came in its box or scan the QR code to visit the modules section of the Opentrons Help Center.", "setup_instructions": "setup instructions", "setup_is_view_only": "Setup is view-only once run has started", "slot_location": "Slot {{slotName}}", "slot_number": "Slot Number", "status": "Status", "step": "STEP {{index}}", - "thermocycler_attention_warning": " Labware must be secured with the module’s latch. See how to secure labware to the Thermocycler Module Thermocycler lid must be open when robot moves to the slots it occupies. Opentrons will automatically open the lid to move to these slots during Labware Position Check.", - "thermocycler_extra_attention_gen_1": "Labware must be secured with the module’s latch. Thermocycler lid must be open when robot moves to the slots it occupies. Opentrons will automatically open the lid to move to these slots during Labware Position Check.", - "thermocycler_extra_attention_gen_2": "The lid will automatically open when moving to these slots during Labware Position Check.", + "there_are_no_unconfigured_modules": "No {{module}} is connected. Attach one and place it in {{slot}}", + "there_are_other_configured_modules": "A {{module}} is already configured in a different slot. Exit run setup and update your deck configuration to move to an already connected module. Or attach another {{module}} to continue setup.", "tip_length_cal_description_bullet": "Perform Tip Length Calibration for each new tip type used on a pipette.", "tip_length_cal_description": "This measures the Z distance between the bottom of the tip and the pipette’s nozzle. If you redo the tip length calibration for the tip you used to calibrate a pipette, you will also have to redo that Pipette Offset Calibration.", "tip_length_cal_title": "Tip Length Calibration", "tip_length_calibration": "tip length calibration", - "total_vol": "total volume", "update_deck": "Update deck", + "update_deck_config": "Update deck configuration", "updated": "Updated", "usb_connected_no_port_info": "USB Port Connected", "usb_port_connected": "USB Port {{port}}", + "usb_port_number": "USB-{{port}}", "value": "Value", "values_are_view_only": "Values are view-only", + "value_out_of_range_generic": "Value must be in range", + "value_out_of_range": "Value must be between {{min}}-{{max}}", "view_current_offsets": "View current offsets", "view_moam": "View setup instructions for placing modules of the same type to the robot.", "view_setup_instructions": "View setup instructions", "volume": "Volume", "what_labware_offset_is": "A Labware Offset is a type of positional adjustment that accounts for small, real-world variances in the overall position of the labware on a robot’s deck. Labware Offset data is unique to a specific combination of labware definition, deck slot, and robot.", - "why_use_lpc": "Labware Position Check is intended to correct for minor variances. Opentrons does not recommend using Labware Position Check to compensate for large positional adjustments. Needing to set large labware offsets could indicate a problem with robot calibration.", "with_the_chosen_value": "With the chosen values, the following error occurred:" } diff --git a/app/src/assets/localization/en/quick_transfer.json b/app/src/assets/localization/en/quick_transfer.json new file mode 100644 index 00000000000..d03c15d2b1b --- /dev/null +++ b/app/src/assets/localization/en/quick_transfer.json @@ -0,0 +1,32 @@ +{ + "all": "All labware", + "aspirate_volume": "Aspirate volume per well (µL)", + "create_new_transfer": "Create new quick transfer", + "left_mount": "Left Mount", + "both_mounts": "Left + Right Mount", + "dispense_volume": "Dispense volume per well (µL)", + "exit_quick_transfer": "Exit quick transfer?", + "lose_all_progress": "You will lose all progress on this quick transfer.", + "right_mount": "Right Mount", + "reservoir": "Reservoirs", + "select_attached_pipette": "Select attached pipette", + "select_dest_labware": "Select destination labware", + "select_dest_wells": "Select destination wells", + "select_source_labware": "Select source labware", + "select_source_wells": "Select source wells", + "select_tip_rack": "Select tip rack", + "set_aspirate_volume": "Set aspirate volume", + "set_dispense_volume": "Set dispense volume", + "set_transfer_volume": "Set transfer volume", + "source_labware": "Source labware in D2", + "use_deck_slots": "Quick transfers use deck slots B2-D2. These slots hold a tip rack, a source labware, and a destination labware.Make sure that your deck configuration is up to date to avoid collisions.", + "tip_rack": "Tip rack", + "tubeRack": "Tube racks", + "volume_per_well": "Volume per well (µL)", + "value_out_of_range": "Value must be between {{min}}-{{max}}", + "labware": "Labware", + "pipette_currently_attached": "Quick transfer options depend on the pipettes currently attached to your robot.", + "wellPlate": "Well plates", + "well_selection": "Well selection", + "well_ratio": "Quick transfers with multiple source wells can either be one-to-one (select {{wells}} for this transfer) or consolidate (select 1 destination well)." +} diff --git a/app/src/assets/localization/en/robot_advanced_settings.json b/app/src/assets/localization/en/robot_advanced_settings.json deleted file mode 100644 index 8ce165ecaa0..00000000000 --- a/app/src/assets/localization/en/robot_advanced_settings.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "download_logs_button": "download", - "download_logs_description": "Access logs from this robot.", - "download_logs_label": "download logs", - "log_opt_out_explanation": "If your OT-2 is connected to the internet, Opentrons will collect logs from your robot to troubleshoot issues and identify error trends.", - "log_opt_out_heading": "Robot Logging", - "log_opt_out_instruction": "If you would like to disable log collection, please click "Opt out" below.", - "open_jupyter_description": "Open the Jupyter Notebook running on this OT-2 in your web browser. (Experimental feature! See documentation for more details.)", - "open_jupyter_label": "Jupyter Notebook", - "opt_in": "Sounds Good!", - "opt_out": "Opt Out", - "reset_button": "reset", - "reset_description": "Restore robot to factory configuration.", - "reset_label": "factory reset", - "title": "advanced settings", - "update_from_file_description": "If your app is unable to auto-download robot updates, you can download the robot update yourself and update your robot manually.", - "update_from_file_label": "Update robot software from file" -} diff --git a/app/src/assets/localization/en/robot_calibration.json b/app/src/assets/localization/en/robot_calibration.json index 9828ed706c4..1e96d8d1c24 100644 --- a/app/src/assets/localization/en/robot_calibration.json +++ b/app/src/assets/localization/en/robot_calibration.json @@ -11,13 +11,11 @@ "calibrate_z_axis_on_block": "Calibrate z-axis on block", "calibrate_z_axis_on_slot": "Calibrate z-axis in slot 5", "calibrate_z_axis_on_trash": "Calibrate z-axis on trash bin", - "calibration_block_description": "This block is a specially made tool that fits perfectly on your deck and helps with calibration.If you do not have a Calibration Block, please email support@opentrons.com so we can send you one. In your message, be sure to include your name, company or institution name, and shipping address. While you wait for the block to arrive, you can use the flat surface on the trash bin of your robot instead.", "calibration_complete": "Calibration complete", "calibration_dashboard": "Calibration Dashboard", "calibration_health_check": "Calibration Health Check", "calibration_health_check_intro_body": "Calibration Health Check diagnoses problems with Deck, Tip Length, and Pipette Offset Calibration.You will move the pipettes to various positions, which will be compared against your existing calibration data.If there is a large difference, you will be prompted to redo some or all of your calibrations.", "calibration_health_check_results": "Calibration Health Check Results", - "calibration_on_opentrons_tips_is_important": "It’s extremely important to perform this calibration using the Opentrons tips and tip racks specified above, as the robot determines accuracy based on the known measurements of these tips.", "calibration_recommended": "Calibration recommended", "calibration_status": "Calibration Status", "calibration_status_description": "For accurate and precise movement, calibrate the robot's deck, pipette offsets, and tip lengths.", @@ -84,8 +82,6 @@ "need_help": "Need help?", "no_pipette": "No pipette attached", "no_tip_length": "Calibrate your pipette to see saved tip length", - "opentrons": "opentrons", - "opentrons_tip_racks_recommended": "Opentrons tip racks are highly recommended. Accuracy cannot be guaranteed with other tip racks.", "pick_up_tip": "Pick up tip", "pipette_name_and_serial": "{{name}}, {{serial}}", "pipette_offset_calibration": "Pipette Offset Calibration", diff --git a/app/src/assets/localization/en/robot_connection.json b/app/src/assets/localization/en/robot_connection.json deleted file mode 100644 index 46d1874d51c..00000000000 --- a/app/src/assets/localization/en/robot_connection.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "connect": "connect", - "connected_description": "Your app is currently connected to your robot via {{type}} at IP address {{ip}}", - "connection_label": "this robot is currently", - "connection_status_default": "idle", - "connection_status_disconnected": "unknown - connect to view status", - "connection_status_not_connectable": "not connectable", - "connection_title": "status", - "disconnect": "disconnect", - "disconnected_description": "Your app is trying to connect to your robot via {{type}} at IP address {{ip}}", - "failed_connection_heading": "Could not connect to robot", - "health_status_not_ok": "not responding correctly to requests", - "health_status_ok": "responding to requests", - "health_status_unreachable": "unreachable", - "internet_status_full": "Internet: The robot is connected to a network and has full access to the Internet.", - "internet_status_limited": "Internet: The robot is connected to a network, but it has no access to the Internet.", - "internet_status_none": "Internet: The robot is not connected to any network.", - "internet_status_portal": "Internet: The robot is behind a captive portal and cannot reach the full Internet.", - "internet_status_unknown": "Internet: Unknown", - "internet_status": "Internet: Unknown", - "ip": "{{type}} IP: {{ip}}", - "last_resort": "If your robot remains unresponsive, please reach out to our Support team.", - "mac": "{{type}} MAC Address: {{mac}}", - "no_server_message": "This OT-2 has been seen recently, but it is currently {{status}} at IP address {{ip}}.We recommend power-cycling your robot.", - "server_message": "Your OT-2's API server is {{status}} at IP address {{ip}}.We recommend the following troubleshooting steps:
  1. Power-cycle your robot
  2. If power-cycling does not work, please update your robot's software
    (Note: your robot's update server is still responding and should accept an update.)
", - "subnet": "{{type}} Subnet Mask: {{subnet}}", - "success_banner": "{{robot}} successfully connected", - "title": "connectivity", - "unresponsive_title": "Unable to establish connection with robot", - "wired": "wired", - "wireless": "wireless" -} diff --git a/app/src/assets/localization/en/robot_info.json b/app/src/assets/localization/en/robot_info.json deleted file mode 100644 index f608623ac4c..00000000000 --- a/app/src/assets/localization/en/robot_info.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "api_version_min_max": "min: {{min}}, max: {{max}}", - "firmware_version": "firmware version", - "robot_name": "robot name", - "server_version": "server version", - "supported_api_versions": "supported protocol API versions", - "title": "information" -} diff --git a/app/src/assets/localization/en/run_details.json b/app/src/assets/localization/en/run_details.json index 90a6977806e..ed0fbbdc7e7 100644 --- a/app/src/assets/localization/en/run_details.json +++ b/app/src/assets/localization/en/run_details.json @@ -5,11 +5,12 @@ "anticipated": "Anticipated steps", "apply_stored_data": "Apply stored data", "apply_stored_labware_offset_data": "Apply stored Labware Offset data?", - "cancel_run_alert_info": "Doing so will terminate this run, drop any attached tips in the trash container and home your robot.", + "cancel_run_alert_info_flex": "Doing so will terminate this run and home your robot.", + "cancel_run_alert_info_ot2": "Doing so will terminate this run, drop any attached tips in the trash container, and home your robot.", "cancel_run_and_restart": "Cancel the run and restart setup to edit", "cancel_run_modal_back": "No, go back", "cancel_run_modal_confirm": "Yes, cancel run", - "cancel_run_modal_heading": "Are you sure you want to cancel this run?", + "cancel_run_modal_heading": "Are you sure you want to cancel?", "cancel_run_module_info": "Additionally, any hardware modules used within the protocol will remain active and maintain their current states until deactivated.", "cancel_run": "Cancel run", "canceling_run_dot": "canceling run...", @@ -22,7 +23,6 @@ "comment_step": "Comment", "comment": "Comment", "complete_protocol_to_download": "Complete the protocol to download the run log", - "contact_information": "Download the robot logs from the Opentrons App and send it to support@opentrons.com for assistance.", "current_step_pause_timer": "Timer", "current_step_pause": "Current Step - Paused by User", "current_step": "Current Step", @@ -101,8 +101,6 @@ "run_completed": "Run completed.", "run_cta_disabled": "Complete required steps on Protocol tab before starting the run", "run_failed_modal_body": "Error occurred when protocol was {{command}}", - "run_failed_modal_description_desktop": "Download the run log and send it to support@opentrons.com for assistance.", - "run_failed_modal_description": "Please contact support@opentrons.com with relevant information for assistance with troubleshooting.", "run_failed_modal_header": "{{errorName}}: {{errorCode}} at protocol step {{count}}", "run_failed_modal_title": "Run failed", "run_failed_splash": "Run failed", diff --git a/app/src/assets/localization/en/shared.json b/app/src/assets/localization/en/shared.json index adb939134f8..5613508b242 100644 --- a/app/src/assets/localization/en/shared.json +++ b/app/src/assets/localization/en/shared.json @@ -11,10 +11,8 @@ "clear_data": "clear data", "close_robot_door": "Close the robot door before starting the run.", "close": "close", - "computer_in_app_is_controlling_robot": "A computer with the Opentrons App is currently controlling this robot.", "confirm_placement": "Confirm placement", "confirm_position": "Confirm position", - "confirm_terminate": "This will immediately stop the activity begun on a computer. You, or another user, may lose progress or see an error in the Opentrons App.", "confirm_values": "Confirm values", "confirm": "Confirm", "continue_activity": "Continue activity", @@ -35,11 +33,9 @@ "exit": "exit", "extension_mount": "extension mount", "flow_complete": "{{flowName}} complete!", - "general_error_message": "If you keep getting this message, try restarting your app and/or robot. If this does not resolve the issue please contact Opentrons Support.", "get_started": "Get started", "github": "GitHub", "go_back": "Go back", - "help_us_improve_send_error_report": "Help us improve your experience by sending an error report to {{support_email}}", "instruments": "instruments", "loading": "Loading...", "next": "Next", diff --git a/app/src/atoms/Banner/Banner.stories.tsx b/app/src/atoms/Banner/Banner.stories.tsx index deea5d236b4..0f3d6210075 100644 --- a/app/src/atoms/Banner/Banner.stories.tsx +++ b/app/src/atoms/Banner/Banner.stories.tsx @@ -1,36 +1,41 @@ import * as React from 'react' import { StyledText, TYPOGRAPHY } from '@opentrons/components' import { Banner } from './index' -import type { Story, Meta } from '@storybook/react' +import type { Meta, StoryObj } from '@storybook/react' -export default { +const meta: Meta = { title: 'App/Atoms/Banner', component: Banner, -} as Meta +} + +export default meta -const Template: Story> = args => ( - {'Banner component'} -) +type Story = StoryObj -export const Primary = Template.bind({}) -Primary.args = { - title: 'title', - type: 'success', +export const Primary: Story = { + args: { + children: 'Banner component', + type: 'success', + }, } -export const OverriddenIcon = Template.bind({}) -OverriddenIcon.args = { - type: 'warning', - title: 'Alert with overridden icon', - icon: { name: 'ot-hot-to-touch' }, + +export const OverriddenIcon: Story = { + args: { + type: 'warning', + children: 'Banner component', + icon: { name: 'ot-hot-to-touch' }, + }, } -export const OverriddenExitIcon = Template.bind({}) -OverriddenExitIcon.args = { - type: 'informing', - title: 'Alert with overriden exit icon', - onCloseClick: () => console.log('close'), - closeButton: ( - - {'Exit'} - - ), + +export const OverriddenExitIcon: Story = { + args: { + type: 'informing', + children: 'Banner component', + onCloseClick: () => console.log('close'), + closeButton: ( + + {'Exit'} + + ), + }, } diff --git a/app/src/atoms/Banner/__tests__/Banner.test.tsx b/app/src/atoms/Banner/__tests__/Banner.test.tsx index 126740f0c4b..f543ec98ec0 100644 --- a/app/src/atoms/Banner/__tests__/Banner.test.tsx +++ b/app/src/atoms/Banner/__tests__/Banner.test.tsx @@ -1,10 +1,9 @@ import * as React from 'react' import { describe, it, vi, expect, beforeEach } from 'vitest' -import '@testing-library/jest-dom/vitest' -import { fireEvent } from '@testing-library/react' +import { fireEvent, screen } from '@testing-library/react' +import { renderWithProviders } from '../../../__testing-utils__' import { i18n } from '../../../i18n' import { Banner } from '..' -import { renderWithProviders } from '../../../__testing-utils__' const render = (props: React.ComponentProps) => { return renderWithProviders(, { @@ -21,60 +20,67 @@ describe('Banner', () => { children: 'TITLE', } }) + it('renders success banner', () => { - const { getByText, getByLabelText } = render(props) - getByLabelText('icon_success') - getByText('TITLE') + render(props) + screen.getByLabelText('icon_success') + screen.getByText('TITLE') }) + it('renders success banner with exit button and when click dismisses banner', () => { props = { type: 'success', children: 'TITLE', onCloseClick: vi.fn(), } - const { getByText, getByLabelText } = render(props) - getByText('TITLE') - const btn = getByLabelText('close_icon') + render(props) + screen.getByText('TITLE') + const btn = screen.getByLabelText('close_icon') fireEvent.click(btn) expect(props.onCloseClick).toHaveBeenCalled() }) + it('renders warning banner', () => { props = { type: 'warning', children: 'TITLE', } - const { getByText, getByLabelText } = render(props) - getByLabelText('icon_warning') - getByText('TITLE') + render(props) + screen.getByLabelText('icon_warning') + screen.getByText('TITLE') }) + it('renders error banner', () => { props = { type: 'error', children: 'TITLE', } - const { getByText, getByLabelText } = render(props) - getByLabelText('icon_error') - getByText('TITLE') + render(props) + screen.getByLabelText('icon_error') + screen.getByText('TITLE') }) + it('renders updating banner', () => { props = { type: 'updating', children: 'TITLE', } - const { getByText, getByLabelText } = render(props) - getByLabelText('icon_updating') - getByText('TITLE') + render(props) + screen.getByLabelText('icon_updating') + screen.getByText('TITLE') }) + it('renders custom icon banner', () => { props = { type: 'warning', children: 'TITLE', icon: { name: 'ot-hot-to-touch' }, } - const { getByText, getByLabelText } = render(props) - getByLabelText('icon_warning') - getByText('TITLE') + render(props) + screen.getByLabelText('icon_warning') + screen.getByText('TITLE') }) + it('renders custom close', () => { props = { type: 'warning', @@ -82,8 +88,8 @@ describe('Banner', () => { closeButton: 'close button', onCloseClick: vi.fn(), } - const { getByText } = render(props) - const btn = getByText('close button') + render(props) + const btn = screen.getByText('close button') fireEvent.click(btn) expect(props.onCloseClick).toHaveBeenCalled() }) diff --git a/app/src/atoms/Banner/index.tsx b/app/src/atoms/Banner/index.tsx index a74fcf829ba..e7d2008521a 100644 --- a/app/src/atoms/Banner/index.tsx +++ b/app/src/atoms/Banner/index.tsx @@ -8,13 +8,12 @@ import { DIRECTION_ROW, Flex, Icon, - IconProps, JUSTIFY_SPACE_BETWEEN, RESPONSIVENESS, SPACING, TYPOGRAPHY, } from '@opentrons/components' -import type { StyleProps } from '@opentrons/components' +import type { IconProps, StyleProps } from '@opentrons/components' export type BannerType = | 'success' diff --git a/app/src/atoms/InputField/InputField.stories.tsx b/app/src/atoms/InputField/InputField.stories.tsx index 9a19201e3b9..677c6c1b048 100644 --- a/app/src/atoms/InputField/InputField.stories.tsx +++ b/app/src/atoms/InputField/InputField.stories.tsx @@ -1,32 +1,78 @@ import * as React from 'react' -import { InputField } from './index' -import type { Story, Meta } from '@storybook/react' +import { + DIRECTION_COLUMN, + Flex, + SPACING, + StyledText, + VIEWPORT, +} from '@opentrons/components' +import { InputField as InputFieldComponent } from './index' +import type { Meta, StoryObj } from '@storybook/react' -export default { +const meta: Meta = { + // ToDo (kk05/02/2024) this should be in Library but at this moment there is the same name component in components + // The unification for this component will be done when the old component is retired completely. title: 'App/Atoms/InputField', - component: InputField, -} as Meta + component: InputFieldComponent, + parameters: VIEWPORT.touchScreenViewport, + argTypes: { + units: { + control: { + type: 'boolean', + }, + }, + }, +} + +export default meta +type Story = StoryObj -const Template: Story> = args => ( - -) +export const InputField: Story = args => { + const [value, setValue] = React.useState(args.value) + return ( + + {'Input title'} + ) => { + setValue(e.target.value) + }} + units={args.units ? 'rem' : undefined} + /> + + ) +} -export const Primary = Template.bind({}) -Primary.args = { +InputField.args = { value: 200, - units: 'rpm', type: 'number', caption: 'example caption', max: 200, - min: 200, + min: 10, } -export const ErrorMessage = Template.bind({}) -ErrorMessage.args = { - units: 'C', +export const InputFieldWithError: Story = args => { + const [value, setValue] = React.useState(args.value) + return ( + + ) => { + setValue(e.target.value) + }} + units={args.type !== 'number' ? undefined : args.units} + /> + + ) +} + +InputFieldWithError.args = { type: 'number', caption: 'example caption', - max: 10, + max: 200, min: 10, - error: 'input does not equal 10', + error: 'input is not in the range', } diff --git a/app/src/atoms/InputField/index.tsx b/app/src/atoms/InputField/index.tsx index c1ff5fbeddd..1177eddc494 100644 --- a/app/src/atoms/InputField/index.tsx +++ b/app/src/atoms/InputField/index.tsx @@ -99,17 +99,19 @@ function Input(props: InputFieldProps): JSX.Element { size = 'small', title, tooltipText, + tabIndex = 0, ...inputProps } = props - const error = props.error != null + const hasError = props.error != null const value = props.isIndeterminate ?? false ? '' : props.value ?? '' const placeHolder = props.isIndeterminate ?? false ? '-' : props.placeholder const [targetProps, tooltipProps] = useHoverTooltip() const OUTER_CSS = css` @media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} { + grid-gap: ${SPACING.spacing8}; &:focus-within { - filter: ${error + filter: ${hasError ? 'none' : `drop-shadow(0px 0px 10px ${COLORS.blue50})`}; } @@ -121,7 +123,7 @@ function Input(props: InputFieldProps): JSX.Element { background-color: ${COLORS.white}; border-radius: ${BORDERS.borderRadius4}; padding: ${SPACING.spacing8}; - border: 1px ${BORDERS.styleSolid} ${error ? COLORS.red50 : COLORS.grey50}; + border: 1px ${BORDERS.styleSolid} ${hasError ? COLORS.red50 : COLORS.grey50}; font-size: ${TYPOGRAPHY.fontSizeP}; width: 100%; height: 2rem; @@ -144,17 +146,19 @@ function Input(props: InputFieldProps): JSX.Element { } &:hover { - border: 1px ${BORDERS.styleSolid} ${error ? COLORS.red50 : COLORS.grey60}; + border: 1px ${BORDERS.styleSolid} + ${hasError ? COLORS.red50 : COLORS.grey60}; } &:focus-visible { - border: 1px ${BORDERS.styleSolid} ${error ? COLORS.red50 : COLORS.grey60}; + border: 1px ${BORDERS.styleSolid} ${COLORS.grey55}; outline: 2px ${BORDERS.styleSolid} ${COLORS.blue50}; - outline-offset: 3px; + outline-offset: 2px; } &:focus-within { - border: 1px ${BORDERS.styleSolid} ${error ? COLORS.red50 : COLORS.blue50}; + border: 1px ${BORDERS.styleSolid} + ${hasError ? COLORS.red50 : COLORS.blue50}; } &:disabled { @@ -168,15 +172,16 @@ function Input(props: InputFieldProps): JSX.Element { @media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} { height: ${size === 'small' ? '4.25rem' : '5rem'}; - box-shadow: ${error ? BORDERS.shadowBig : 'none'}; + box-shadow: ${hasError ? BORDERS.shadowBig : 'none'}; font-size: ${TYPOGRAPHY.fontSize28}; padding: ${SPACING.spacing16} ${SPACING.spacing24}; - border: 2px ${BORDERS.styleSolid} ${error ? COLORS.red50 : COLORS.grey50}; + border: 2px ${BORDERS.styleSolid} + ${hasError ? COLORS.red50 : COLORS.grey50}; &:focus-within { box-shadow: none; - border: ${error ? '2px' : '3px'} ${BORDERS.styleSolid} - ${error ? COLORS.red50 : COLORS.blue50}; + border: ${hasError ? '2px' : '3px'} ${BORDERS.styleSolid} + ${hasError ? COLORS.red50 : COLORS.blue50}; } & input { @@ -191,19 +196,17 @@ function Input(props: InputFieldProps): JSX.Element { ` const FORM_BOTTOM_SPACE_STYLE = css` - padding: ${SPACING.spacing4} 0rem; + padding-top: ${SPACING.spacing4}; @media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} { + padding: ${SPACING.spacing8} 0rem; padding-bottom: 0; } ` const TITLE_STYLE = css` - color: ${error ? COLORS.red50 : COLORS.black90}; + color: ${hasError ? COLORS.red50 : COLORS.black90}; padding-bottom: ${SPACING.spacing8}; - font-size: ${TYPOGRAPHY.fontSizeLabel}; - font-weight: ${TYPOGRAPHY.fontWeightSemiBold}; - line-height: ${TYPOGRAPHY.lineHeight12}; - align-text: ${textAlign}; + text-align: ${textAlign}; @media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} { font-size: ${TYPOGRAPHY.fontSize22}; font-weight: ${TYPOGRAPHY.fontWeightRegular}; @@ -214,9 +217,11 @@ function Input(props: InputFieldProps): JSX.Element { const ERROR_TEXT_STYLE = css` color: ${COLORS.red50}; + padding-top: ${SPACING.spacing4}; @media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} { font-size: ${TYPOGRAPHY.fontSize22}; color: ${COLORS.red50}; + padding-top: ${SPACING.spacing8}; } ` @@ -239,9 +244,14 @@ function Input(props: InputFieldProps): JSX.Element { {title != null ? ( - + {title} - + {tooltipText != null ? ( <> @@ -258,6 +268,7 @@ function Input(props: InputFieldProps): JSX.Element { ) : null} { @@ -277,16 +288,6 @@ function Input(props: InputFieldProps): JSX.Element { {props.units} ) : null} - {props.error != null ? ( - - {props.error} - - ) : null} {props.caption != null ? ( ) : null} + {hasError ? ( + + {props.error} + + ) : null} ) } diff --git a/app/src/atoms/Link/ExternalLink.stories.tsx b/app/src/atoms/Link/ExternalLink.stories.tsx index c243304ee59..8f664d257f5 100644 --- a/app/src/atoms/Link/ExternalLink.stories.tsx +++ b/app/src/atoms/Link/ExternalLink.stories.tsx @@ -1,22 +1,26 @@ import * as React from 'react' -import { Flex, COLORS } from '@opentrons/components' -import { ExternalLink } from './ExternalLink' +import { COLORS, Flex, SPACING } from '@opentrons/components' +import { ExternalLink as ExternalLinkComponent } from './ExternalLink' -import type { Story, Meta } from '@storybook/react' +import type { Meta, StoryObj } from '@storybook/react' -export default { +const meta: Meta = { title: 'App/Atoms/ExternalLink', - component: ExternalLink, -} as Meta - -const Template: Story> = args => ( - - - -) + component: ExternalLinkComponent, + decorators: [ + Story => ( + + + + ), + ], +} +export default meta +type Story = StoryObj -export const Primary = Template.bind({}) -Primary.args = { - href: 'https://www.opentrons.com', - children: 'Open the link', +export const ExternalLink: Story = { + args: { + href: 'https://www.opentrons.com', + children: 'Open the link', + }, } diff --git a/app/src/atoms/Link/ExternalLink.tsx b/app/src/atoms/Link/ExternalLink.tsx index 4baa78afa44..e35e3515277 100644 --- a/app/src/atoms/Link/ExternalLink.tsx +++ b/app/src/atoms/Link/ExternalLink.tsx @@ -1,12 +1,7 @@ import * as React from 'react' -import { - Link, - LinkProps, - Icon, - TYPOGRAPHY, - SPACING, -} from '@opentrons/components' +import { Link, Icon, TYPOGRAPHY, SPACING } from '@opentrons/components' +import type { LinkProps } from '@opentrons/components' export interface ExternalLinkProps extends LinkProps { href: string diff --git a/app/src/atoms/Link/__tests__/ExternalLink.test.tsx b/app/src/atoms/Link/__tests__/ExternalLink.test.tsx index f89572e2429..6d39662a104 100644 --- a/app/src/atoms/Link/__tests__/ExternalLink.test.tsx +++ b/app/src/atoms/Link/__tests__/ExternalLink.test.tsx @@ -29,7 +29,7 @@ describe('ExternalLink', () => { const link = screen.getByText('Test Link') expect(link).toHaveAttribute('href', 'https://opentrons.com') expect(link).toHaveAttribute('target', '_blank') - expect(link).toHaveStyle(`color: ${COLORS.blue55}`) + expect(link).toHaveStyle(`color: ${COLORS.blue50}`) }) it('renders open-in-new icon', () => { diff --git a/app/src/atoms/MenuList/DropdownMenu.tsx b/app/src/atoms/MenuList/DropdownMenu.tsx index 7eafba80ecb..5d9d82d7d7f 100644 --- a/app/src/atoms/MenuList/DropdownMenu.tsx +++ b/app/src/atoms/MenuList/DropdownMenu.tsx @@ -15,7 +15,9 @@ import { TYPOGRAPHY, useOnClickOutside, POSITION_RELATIVE, + useHoverTooltip, } from '@opentrons/components' +import { Tooltip } from '../Tooltip' import { MenuItem } from './MenuItem' export interface DropdownOption { @@ -26,13 +28,24 @@ export interface DropdownOption { export type DropdownBorder = 'rounded' | 'neutral' export interface DropdownMenuProps { + /** dropdown options */ filterOptions: DropdownOption[] + /** click handler */ onClick: (value: string) => void + /** current selected option */ currentOption: DropdownOption + /** dropdown */ width?: string + /** dropdown style type */ dropdownType?: DropdownBorder + /** dropdown title */ title?: string + /** dropdown item caption */ caption?: string | null + /** text for tooltip */ + tooltipText?: string + /** html tabindex property */ + tabIndex?: number } // TODO: (smb: 4/15/22) refactor this to use html select for accessibility @@ -46,7 +59,10 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element { dropdownType = 'rounded', title, caption, + tooltipText, + tabIndex = 0, } = props + const [targetProps, tooltipProps] = useHoverTooltip() const [showDropdownMenu, setShowDropdownMenu] = React.useState(false) const toggleSetShowDropdownMenu = (): void => { setShowDropdownMenu(!showDropdownMenu) @@ -96,13 +112,27 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element { return ( {title !== null ? ( - - {title} - + + + {title} + + {tooltipText != null ? ( + <> + + + + {tooltipText} + + ) : null} + ) : null} { }) expect(getByRole('button')).toHaveStyle( - `background-color: ${COLORS.grey35}` - ) - }) - - it('renders an active state', () => { - const { getByRole } = render({ - onClick: vi.fn(), - }) - - expect(getByRole('button')).toHaveStyle( - `background-color: ${String(COLORS.grey35)}` - ) - }) - - it.skip('renders a focus state', () => { - const { getByRole } = render({ - onClick: vi.fn(), - }) - - // @ts-expect-error Refactor to test modifier states. - expect(getByRole('button')).toHaveStyleRule( - 'box-shadow', - `0 0 0 3px ${String(COLORS.yellow50)}`, - { - modifier: ':focus-visible', - } - ) - }) - - it.skip('renders a disabled state', () => { - const { getByRole } = render({ - onClick: vi.fn(), - }) - - // @ts-expect-error Refactor to test modifier states. - expect(getByRole('button')).toHaveStyleRule( - 'fill', - `${String(COLORS.grey40)}`, - { - modifier: ':disabled circle', - } + `background-color: ${COLORS.transparent}` ) }) }) diff --git a/app/src/atoms/Slideout/MultiSlideout.tsx b/app/src/atoms/Slideout/MultiSlideout.tsx index 71ce02f6de6..73054a10a45 100644 --- a/app/src/atoms/Slideout/MultiSlideout.tsx +++ b/app/src/atoms/Slideout/MultiSlideout.tsx @@ -1,16 +1,9 @@ import * as React from 'react' import { Slideout } from './index' -interface MultiSlideoutProps { - title: string | React.ReactElement - children: React.ReactNode - onCloseClick: () => void - currentStep: number - maxSteps: number - // isExpanded is for collapse and expand animation - isExpanded?: boolean - footer?: React.ReactNode -} +import type { MultiSlideoutSpecs, SlideoutProps } from './index' + +type MultiSlideoutProps = SlideoutProps & MultiSlideoutSpecs export const MultiSlideout = (props: MultiSlideoutProps): JSX.Element => { const { diff --git a/app/src/atoms/SoftwareKeyboard/AlphanumericKeyboard/index.tsx b/app/src/atoms/SoftwareKeyboard/AlphanumericKeyboard/index.tsx index 5698e49f1e6..dccad085c08 100644 --- a/app/src/atoms/SoftwareKeyboard/AlphanumericKeyboard/index.tsx +++ b/app/src/atoms/SoftwareKeyboard/AlphanumericKeyboard/index.tsx @@ -1,6 +1,7 @@ import * as React from 'react' import Keyboard from 'react-simple-keyboard' import { alphanumericKeyboardLayout, customDisplay } from '../constants' +import type { KeyboardReactInterface } from 'react-simple-keyboard' import '../index.css' import './index.css' @@ -8,7 +9,7 @@ import './index.css' // TODO (kk:04/05/2024) add debug to make debugging easy interface AlphanumericKeyboardProps { onChange: (input: string) => void - keyboardRef: React.MutableRefObject + keyboardRef: React.MutableRefObject debug?: boolean } diff --git a/app/src/atoms/SoftwareKeyboard/FullKeyboard/index.tsx b/app/src/atoms/SoftwareKeyboard/FullKeyboard/index.tsx index 69c5c748d3a..663efdd9c24 100644 --- a/app/src/atoms/SoftwareKeyboard/FullKeyboard/index.tsx +++ b/app/src/atoms/SoftwareKeyboard/FullKeyboard/index.tsx @@ -1,6 +1,7 @@ import * as React from 'react' import { KeyboardReact as Keyboard } from 'react-simple-keyboard' import { customDisplay, fullKeyboardLayout } from '../constants' +import type { KeyboardReactInterface } from 'react-simple-keyboard' import '../index.css' import './index.css' @@ -8,7 +9,7 @@ import './index.css' // TODO (kk:04/05/2024) add debug to make debugging easy interface FullKeyboardProps { onChange: (input: string) => void - keyboardRef: React.MutableRefObject + keyboardRef: React.MutableRefObject debug?: boolean } diff --git a/app/src/atoms/SoftwareKeyboard/IndividualKey/index.tsx b/app/src/atoms/SoftwareKeyboard/IndividualKey/index.tsx index 9ff8c278423..310008cddc8 100644 --- a/app/src/atoms/SoftwareKeyboard/IndividualKey/index.tsx +++ b/app/src/atoms/SoftwareKeyboard/IndividualKey/index.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { KeyboardReact as Keyboard } from 'react-simple-keyboard' - +import type { KeyboardReactInterface } from 'react-simple-keyboard' import '../index.css' import './index.css' @@ -11,7 +11,7 @@ const customDisplay = { // TODO (kk:04/05/2024) add debug to make debugging easy interface IndividualKeyProps { onChange: (input: string) => void - keyboardRef: React.MutableRefObject + keyboardRef: React.MutableRefObject keyText: string debug?: boolean } diff --git a/app/src/atoms/SoftwareKeyboard/NumericalKeyboard/NumericalKeyboard.stories.tsx b/app/src/atoms/SoftwareKeyboard/NumericalKeyboard/NumericalKeyboard.stories.tsx index d7659866c6a..53b3d714c4c 100644 --- a/app/src/atoms/SoftwareKeyboard/NumericalKeyboard/NumericalKeyboard.stories.tsx +++ b/app/src/atoms/SoftwareKeyboard/NumericalKeyboard/NumericalKeyboard.stories.tsx @@ -37,7 +37,6 @@ type Story = StoryObj const Keyboard = (args): JSX.Element => { const { isDecimal, hasHyphen } = args - console.log(isDecimal, hasHyphen) const [showKeyboard, setShowKeyboard] = React.useState(false) const [value, setValue] = React.useState('') const keyboardRef = React.useRef(null) diff --git a/app/src/atoms/SoftwareKeyboard/NumericalKeyboard/index.css b/app/src/atoms/SoftwareKeyboard/NumericalKeyboard/index.css index 28fe3159979..3df1453b84c 100644 --- a/app/src/atoms/SoftwareKeyboard/NumericalKeyboard/index.css +++ b/app/src/atoms/SoftwareKeyboard/NumericalKeyboard/index.css @@ -10,6 +10,7 @@ .simple-keyboard.oddTheme1.hg-theme-default { width: 100%; height: 100%; + border-radius: 0; background-color: #cbcccc; /* grey35 */ font-family: 'Public Sans', sans-serif; padding: 8px; diff --git a/app/src/atoms/SoftwareKeyboard/NumericalKeyboard/index.tsx b/app/src/atoms/SoftwareKeyboard/NumericalKeyboard/index.tsx index 9065bcce44f..8c41120d536 100644 --- a/app/src/atoms/SoftwareKeyboard/NumericalKeyboard/index.tsx +++ b/app/src/atoms/SoftwareKeyboard/NumericalKeyboard/index.tsx @@ -1,13 +1,15 @@ import * as React from 'react' import { KeyboardReact as Keyboard } from 'react-simple-keyboard' import { numericalKeyboardLayout, numericalCustom } from '../constants' + +import type { KeyboardReactInterface } from 'react-simple-keyboard' import '../index.css' import './index.css' // Note (kk:04/05/2024) add debug to make debugging easy interface NumericalKeyboardProps { onChange: (input: string) => void - keyboardRef: React.MutableRefObject + keyboardRef: React.MutableRefObject isDecimal?: boolean hasHyphen?: boolean debug?: boolean diff --git a/app/src/atoms/buttons/LargeButton.stories.tsx b/app/src/atoms/buttons/LargeButton.stories.tsx index fa3a5e9d2fb..d60e89d81f3 100644 --- a/app/src/atoms/buttons/LargeButton.stories.tsx +++ b/app/src/atoms/buttons/LargeButton.stories.tsx @@ -45,3 +45,16 @@ export const Alert: Story = { iconName: 'reset', }, } +export const PrimaryNoIcon: Story = { + args: { + buttonText: 'Button text', + disabled: false, + }, +} +export const PrimaryWithSubtext: Story = { + args: { + buttonText: 'Button text', + disabled: false, + subtext: 'Button subtext', + }, +} diff --git a/app/src/atoms/buttons/LargeButton.tsx b/app/src/atoms/buttons/LargeButton.tsx index 6bfcf857d84..c5e45d3b731 100644 --- a/app/src/atoms/buttons/LargeButton.tsx +++ b/app/src/atoms/buttons/LargeButton.tsx @@ -7,6 +7,7 @@ import { DIRECTION_COLUMN, DISPLAY_FLEX, Icon, + Flex, JUSTIFY_SPACE_BETWEEN, SPACING, StyledText, @@ -20,7 +21,8 @@ interface LargeButtonProps extends StyleProps { onClick: () => void buttonType?: LargeButtonTypes buttonText: React.ReactNode - iconName: IconName + iconName?: IconName + subtext?: string disabled?: boolean } @@ -29,6 +31,7 @@ export function LargeButton(props: LargeButtonProps): JSX.Element { buttonType = 'primary', buttonText, iconName, + subtext, disabled = false, ...buttonProps } = props @@ -110,23 +113,28 @@ export function LargeButton(props: LargeButtonProps): JSX.Element { disabled={disabled} {...buttonProps} > - - {buttonText} - - + + + {buttonText} + + {subtext ? ( + + {subtext} + + ) : null} + + {iconName ? ( + + ) : null} ) } diff --git a/app/src/atoms/buttons/__tests__/FloatingActionButton.test.tsx b/app/src/atoms/buttons/__tests__/FloatingActionButton.test.tsx index 7e62b0f8662..af9860abce6 100644 --- a/app/src/atoms/buttons/__tests__/FloatingActionButton.test.tsx +++ b/app/src/atoms/buttons/__tests__/FloatingActionButton.test.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { describe, it, expect, vi, beforeEach } from 'vitest' import '@testing-library/jest-dom/vitest' -import { fireEvent, screen } from '@testing-library/react' +import { screen } from '@testing-library/react' import { BORDERS, COLORS, SPACING, TYPOGRAPHY } from '@opentrons/components' import { i18n } from '../../../i18n' @@ -30,7 +30,7 @@ describe('FloatingActionButton', () => { expect(button).toHaveStyle( `padding: ${SPACING.spacing12} ${SPACING.spacing24}` ) - expect(button).toHaveStyle(`background-color: ${COLORS.purple55}`) + expect(button).toHaveStyle(`background-color: ${COLORS.purple50}`) expect(button).toHaveStyle(`font-size: ${TYPOGRAPHY.fontSize28}`) expect(button).toHaveStyle(`font-weight: ${TYPOGRAPHY.fontWeightSemiBold}`) expect(button).toHaveStyle(`line-height: ${TYPOGRAPHY.lineHeight36}`) @@ -47,14 +47,5 @@ describe('FloatingActionButton', () => { render(props) const button = screen.getByRole('button') expect(button).toBeDisabled() - expect(button).toHaveStyle(`background-color: ${COLORS.grey35}`) - expect(button).toHaveStyle(`color: ${COLORS.grey50}`) - }) - - it('applies the correct states to the unselected floating action button - active', () => { - render(props) - const button = screen.getByRole('button') - fireEvent.mouseLeave(button) - expect(button).toHaveStyle(`background-color : ${COLORS.purple55}`) }) }) diff --git a/app/src/atoms/buttons/__tests__/LargeButton.test.tsx b/app/src/atoms/buttons/__tests__/LargeButton.test.tsx index 945dce27823..86576cb1381 100644 --- a/app/src/atoms/buttons/__tests__/LargeButton.test.tsx +++ b/app/src/atoms/buttons/__tests__/LargeButton.test.tsx @@ -24,9 +24,6 @@ describe('LargeButton', () => { render(props) fireEvent.click(screen.getByText('large button')) expect(props.onClick).toHaveBeenCalled() - expect(screen.getByRole('button')).toHaveStyle( - `background-color: ${COLORS.blue60}` - ) }) it('renders the alert button', () => { props = { @@ -35,7 +32,7 @@ describe('LargeButton', () => { } render(props) expect(screen.getByRole('button')).toHaveStyle( - `background-color: ${COLORS.red40}` + `background-color: ${COLORS.red35}` ) }) it('renders the secondary button', () => { @@ -45,7 +42,7 @@ describe('LargeButton', () => { } render(props) expect(screen.getByRole('button')).toHaveStyle( - `background-color: ${COLORS.blue40}` + `background-color: ${COLORS.blue35}` ) }) it('renders the button as disabled', () => { diff --git a/app/src/atoms/buttons/__tests__/MediumButton.test.tsx b/app/src/atoms/buttons/__tests__/MediumButton.test.tsx index f4d23ea3a32..1c85bf34eb1 100644 --- a/app/src/atoms/buttons/__tests__/MediumButton.test.tsx +++ b/app/src/atoms/buttons/__tests__/MediumButton.test.tsx @@ -24,7 +24,6 @@ describe('MediumButton', () => { render(props) fireEvent.click(screen.getByText('Medium button')) expect(props.onClick).toHaveBeenCalled() - expect(screen.getByRole('button')).toHaveStyle('background-color: #045dd0') }) it('renders the alert button', () => { props = { @@ -32,7 +31,9 @@ describe('MediumButton', () => { buttonType: 'alert', } render(props) - expect(screen.getByRole('button')).toHaveStyle('background-color: #b91f20') + expect(screen.getByRole('button')).toHaveStyle( + `background-color: ${COLORS.red50}` + ) }) it('renders the secondary button', () => { props = { @@ -40,7 +41,9 @@ describe('MediumButton', () => { buttonType: 'secondary', } render(props) - expect(screen.getByRole('button')).toHaveStyle('background-color: #94afd4') + expect(screen.getByRole('button')).toHaveStyle( + `background-color: ${COLORS.blue35}` + ) }) it('renders the secondary alert button', () => { props = { @@ -48,7 +51,9 @@ describe('MediumButton', () => { buttonType: 'alertSecondary', } render(props) - expect(screen.getByRole('button')).toHaveStyle('background-color: #ccabac') + expect(screen.getByRole('button')).toHaveStyle( + `background-color: ${COLORS.red35}` + ) }) it('renders the tertiary high button', () => { props = { @@ -57,7 +62,7 @@ describe('MediumButton', () => { } render(props) expect(screen.getByRole('button')).toHaveStyle( - `background-color: ${COLORS.grey35}` + `background-color: ${COLORS.white}` ) }) it('renders the tertiary low light button', () => { @@ -67,7 +72,7 @@ describe('MediumButton', () => { } render(props) expect(screen.getByRole('button')).toHaveStyle( - `background-color: ${COLORS.grey35}` + `background-color: ${COLORS.white}` ) }) it('renders the button as disabled', () => { diff --git a/app/src/atoms/buttons/__tests__/QuaternaryButton.test.tsx b/app/src/atoms/buttons/__tests__/QuaternaryButton.test.tsx index 978f46e3c08..e9dd204ca2f 100644 --- a/app/src/atoms/buttons/__tests__/QuaternaryButton.test.tsx +++ b/app/src/atoms/buttons/__tests__/QuaternaryButton.test.tsx @@ -1,12 +1,19 @@ import * as React from 'react' import '@testing-library/jest-dom/vitest' -import { describe, it, expect, beforeEach } from 'vitest' -import { screen, fireEvent } from '@testing-library/react' +import { describe, it, expect, beforeEach, vi } from 'vitest' +import { screen } from '@testing-library/react' import { COLORS, SPACING, TYPOGRAPHY, BORDERS } from '@opentrons/components' import { renderWithProviders } from '../../../__testing-utils__' import { QuaternaryButton } from '..' +vi.mock('styled-components', async () => { + const actual = await vi.importActual( + 'styled-components/dist/styled-components.browser.esm.js' + ) + return actual +}) + const render = (props: React.ComponentProps) => { return renderWithProviders()[0] } @@ -25,7 +32,7 @@ describe('QuaternaryButton', () => { const button = screen.getByText('secondary tertiary button') expect(button).toHaveStyle(`background-color: ${COLORS.white}`) expect(button).toHaveStyle(`border-radius: ${BORDERS.borderRadiusFull}`) - expect(button).toHaveStyle('box-shadow: 0 0 0') + expect(button).toHaveStyle('box-shadow: none') expect(button).toHaveStyle(`color: ${COLORS.blue50}`) expect(button).toHaveStyle( `padding: ${SPACING.spacing8} ${SPACING.spacing16} ${SPACING.spacing8} ${SPACING.spacing16}` @@ -47,14 +54,6 @@ describe('QuaternaryButton', () => { expect(button).toHaveStyle('opacity: 50%') }) - it('applies the correct states to the button - hover', () => { - render(props) - const button = screen.getByText('secondary tertiary button') - fireEvent.mouseOver(button) - expect(button).toHaveStyle('opacity: 70%') - expect(button).toHaveStyle('box-shadow: 0 0 0') - }) - it('renders secondary tertiary button with text and different background color', () => { props.color = COLORS.red50 render(props) diff --git a/app/src/atoms/buttons/__tests__/RadioButton.test.tsx b/app/src/atoms/buttons/__tests__/RadioButton.test.tsx index da44e16dffd..2f6e29103bd 100644 --- a/app/src/atoms/buttons/__tests__/RadioButton.test.tsx +++ b/app/src/atoms/buttons/__tests__/RadioButton.test.tsx @@ -27,7 +27,7 @@ describe('RadioButton', () => { } render(props) const label = screen.getByRole('label') - expect(label).toHaveStyle(`background-color: ${COLORS.blue40}`) + expect(label).toHaveStyle(`background-color: ${COLORS.blue35}`) expect(label).toHaveStyle(`padding: ${SPACING.spacing24}`) }) it('renders the large selected button', () => { @@ -38,7 +38,7 @@ describe('RadioButton', () => { } render(props) const label = screen.getByRole('label') - expect(label).toHaveStyle(`background-color: ${COLORS.blue60}`) + expect(label).toHaveStyle(`background-color: ${COLORS.blue50}`) expect(label).toHaveStyle(`padding: ${SPACING.spacing24}`) }) it('renders the small button', () => { @@ -48,7 +48,7 @@ describe('RadioButton', () => { } render(props) const label = screen.getByRole('label') - expect(label).toHaveStyle(`background-color: ${COLORS.blue40}`) + expect(label).toHaveStyle(`background-color: ${COLORS.blue35}`) expect(label).toHaveStyle(`padding: ${SPACING.spacing20}`) }) it('renders the small selected button', () => { @@ -59,7 +59,7 @@ describe('RadioButton', () => { } render(props) const label = screen.getByRole('label') - expect(label).toHaveStyle(`background-color: ${COLORS.blue60}`) + expect(label).toHaveStyle(`background-color: ${COLORS.blue50}`) expect(label).toHaveStyle(`padding: ${SPACING.spacing20}`) }) }) diff --git a/app/src/atoms/buttons/__tests__/SmallButton.test.tsx b/app/src/atoms/buttons/__tests__/SmallButton.test.tsx index 2aa55acef6e..9c3e03f9b04 100644 --- a/app/src/atoms/buttons/__tests__/SmallButton.test.tsx +++ b/app/src/atoms/buttons/__tests__/SmallButton.test.tsx @@ -25,7 +25,7 @@ describe('SmallButton', () => { fireEvent.click(screen.getByText('small button')) expect(props.onClick).toHaveBeenCalled() expect(screen.getByRole('button')).toHaveStyle( - `background-color: ${COLORS.blue60}` + `background-color: ${COLORS.blue50}` ) expect(screen.getByRole('button')).toHaveStyle( `border-radius: ${BORDERS.borderRadius16}` @@ -38,7 +38,7 @@ describe('SmallButton', () => { } render(props) expect(screen.getByRole('button')).toHaveStyle( - `background-color: ${COLORS.red55}` + `background-color: ${COLORS.red50}` ) }) it('renders the secondary button', () => { @@ -48,7 +48,7 @@ describe('SmallButton', () => { } render(props) expect(screen.getByRole('button')).toHaveStyle( - `background-color: ${COLORS.blue40}` + `background-color: ${COLORS.blue35}` ) }) it('renders the tertiary high light button', () => { diff --git a/app/src/atoms/buttons/__tests__/SubmitPrimaryButton.test.tsx b/app/src/atoms/buttons/__tests__/SubmitPrimaryButton.test.tsx index 40f61eeef13..c4d33d2aef5 100644 --- a/app/src/atoms/buttons/__tests__/SubmitPrimaryButton.test.tsx +++ b/app/src/atoms/buttons/__tests__/SubmitPrimaryButton.test.tsx @@ -28,7 +28,7 @@ describe('SubmitPrimaryButton', () => { it('renders submit primary button with text - active', () => { render(props) const button = screen.getByText('submit primary button') - expect(button).toHaveStyle(`background-color: ${COLORS.blue60}`) + expect(button).toHaveStyle(`background-color: ${COLORS.blue50}`) expect(button).toHaveStyle(`border-radius: ${BORDERS.borderRadius8}`) expect(button).toHaveStyle( `padding: ${SPACING.spacing8} ${SPACING.spacing16}` diff --git a/app/src/atoms/buttons/__tests__/TabbedButton.test.tsx b/app/src/atoms/buttons/__tests__/TabbedButton.test.tsx index 893b71ab904..2a5ef52551d 100644 --- a/app/src/atoms/buttons/__tests__/TabbedButton.test.tsx +++ b/app/src/atoms/buttons/__tests__/TabbedButton.test.tsx @@ -23,7 +23,7 @@ describe('Unselected TabbedButton', () => { it('renders unselected tabbed button with text', () => { render(props) const button = screen.getByText('tabbed button') - expect(button).toHaveStyle(`background-color: ${COLORS.purple40}`) + expect(button).toHaveStyle(`background-color: ${COLORS.purple35}`) expect(button).toHaveStyle( `padding: ${SPACING.spacing16} ${SPACING.spacing24}` ) @@ -68,7 +68,7 @@ describe('Selected TabbedButton', () => { it('renders selected tabbed button with text', () => { render(props) const button = screen.getByText('tabbed button') - expect(button).toHaveStyle(`background-color: ${COLORS.purple55}`) + expect(button).toHaveStyle(`background-color: ${COLORS.purple50}`) expect(button).toHaveStyle( `padding: ${SPACING.spacing16} ${SPACING.spacing24}` ) diff --git a/app/src/atoms/buttons/__tests__/TertiaryButton.test.tsx b/app/src/atoms/buttons/__tests__/TertiaryButton.test.tsx index 4c0b2b97a1e..11790f63c47 100644 --- a/app/src/atoms/buttons/__tests__/TertiaryButton.test.tsx +++ b/app/src/atoms/buttons/__tests__/TertiaryButton.test.tsx @@ -22,7 +22,7 @@ describe('TertiaryButton', () => { it('renders tertiary button with text', () => { render(props) const button = screen.getByText('tertiary button') - expect(button).toHaveStyle(`background-color: ${COLORS.blue60}`) + expect(button).toHaveStyle(`background-color: ${COLORS.blue50}`) expect(button).toHaveStyle( `padding: ${SPACING.spacing8} ${SPACING.spacing16} ${SPACING.spacing8} ${SPACING.spacing16}` ) @@ -52,7 +52,7 @@ describe('TertiaryButton', () => { props.backgroundColor = COLORS.red50 render(props) const button = screen.getByText('tertiary button') - expect(button).toHaveStyle(`background-color: ${COLORS.blue60}`) + expect(button).toHaveStyle(`background-color: ${COLORS.red50}`) expect(button).toHaveStyle(`color: ${COLORS.white}`) }) }) diff --git a/app/src/atoms/buttons/__tests__/ToggleButton.test.tsx b/app/src/atoms/buttons/__tests__/ToggleButton.test.tsx index d9aa36d565a..bc47fabe48c 100644 --- a/app/src/atoms/buttons/__tests__/ToggleButton.test.tsx +++ b/app/src/atoms/buttons/__tests__/ToggleButton.test.tsx @@ -28,7 +28,7 @@ describe('ToggleButton', () => { it('renders toggle button - on', () => { render(props) const button = screen.getByLabelText('toggle button') - expect(button).toHaveStyle(`color: ${COLORS.blue55}`) + expect(button).toHaveStyle(`color: ${COLORS.blue50}`) expect(button).toHaveStyle(`height: ${SIZE_2}`) expect(button).toHaveStyle(`width: ${SIZE_2}`) expect(button).toHaveAttribute('aria-checked', 'true') @@ -52,7 +52,7 @@ describe('ToggleButton', () => { props.toggledOn = false render(props) const button = screen.getByLabelText('toggle button') - expect(button).toHaveStyle(`color: ${COLORS.grey55}`) + expect(button).toHaveStyle(`color: ${COLORS.grey50}`) expect(button).toHaveStyle(`height: ${SIZE_2}`) expect(button).toHaveStyle(`width: ${SIZE_2}`) expect(button).toHaveAttribute('aria-checked', 'false') diff --git a/app/src/i18n.ts b/app/src/i18n.ts index 9e03af972c0..38bb6803b45 100644 --- a/app/src/i18n.ts +++ b/app/src/i18n.ts @@ -5,49 +5,43 @@ import { initReactI18next } from 'react-i18next' import { resources } from './assets/localization' import { titleCase } from '@opentrons/shared-data' -i18n.use(initReactI18next).init( - { - resources, - lng: 'en', - fallbackLng: 'en', - debug: process.env.NODE_ENV === 'development', - ns: [ - 'shared', - 'robot_advanced_settings', - 'robot_calibration', - 'robot_connection', - 'robot_controls', - 'robot_info', - 'top_navigation', - ], - defaultNS: 'shared', - interpolation: { - escapeValue: false, // not needed for react as it escapes by default - format: function (value, format, lng) { - if (format === 'upperCase') return value.toUpperCase() - if (format === 'lowerCase') return value.toLowerCase() - if (format === 'capitalize') return capitalize(value) - if (format === 'sentenceCase') return startCase(value) - if (format === 'titleCase') return titleCase(value) - return value - }, - }, - keySeparator: false, // use namespaces and context instead - saveMissing: true, - missingKeyHandler: (lng, ns, key) => { - process.env.NODE_ENV === 'test' - ? console.error(`Missing ${lng} Translation: key={${key}} ns={${ns}}`) - : console.warn(`Missing ${lng} Translation: key={${key}} ns={${ns}}`) +import type { InitOptions } from 'i18next' + +const i18nConfig: InitOptions = { + resources, + lng: 'en', + fallbackLng: 'en', + debug: process.env.NODE_ENV === 'development', + defaultNS: 'shared', + interpolation: { + escapeValue: false, // not needed for react as it escapes by default + format: function (value, format, lng) { + if (format === 'upperCase') return value.toUpperCase() + if (format === 'lowerCase') return value.toLowerCase() + if (format === 'capitalize') return capitalize(value) + if (format === 'sentenceCase') return startCase(value) + if (format === 'titleCase') return titleCase(value) + return value }, }, - err => { - if (err) { - console.error( - 'Internationalization was not initialized properly. error: ', - err - ) - } + keySeparator: false, // use namespaces and context instead + saveMissing: true, + missingKeyHandler: (lng, ns, key) => { + process.env.NODE_ENV === 'test' + ? console.error(`Missing ${lng} Translation: key={${key}} ns={${ns}}`) + : console.warn(`Missing ${lng} Translation: key={${key}} ns={${ns}}`) + }, +} + +const i18nCb = (err?: Error): void => { + if (err != null) { + console.error( + 'Internationalization was not initialized properly. error: ', + err + ) } -) +} + +void i18n.use(initReactI18next).init(i18nConfig, i18nCb) -export { i18n } +export { i18n, i18nCb, i18nConfig } diff --git a/app/src/index.tsx b/app/src/index.tsx index f6f4918d769..e37435c9aba 100644 --- a/app/src/index.tsx +++ b/app/src/index.tsx @@ -5,10 +5,8 @@ import { Provider } from 'react-redux' import { ConnectedRouter } from 'connected-react-router' -import { I18nextProvider } from 'react-i18next' import { ApiClientProvider } from '@opentrons/react-api-client' -import { i18n } from './i18n' import { createLogger } from './logger' import { uiInitialized } from './redux/shell' @@ -38,9 +36,7 @@ root.render( - - - + diff --git a/app/src/molecules/CardButton/__tests__/CardButton.test.tsx b/app/src/molecules/CardButton/__tests__/CardButton.test.tsx index bcffe52df26..80d17c32d08 100644 --- a/app/src/molecules/CardButton/__tests__/CardButton.test.tsx +++ b/app/src/molecules/CardButton/__tests__/CardButton.test.tsx @@ -49,7 +49,7 @@ describe('CardButton', () => { screen.getByText('Find a network in your lab or enter your own.') expect(screen.getByTestId('cardButton_icon_wifi')).toBeInTheDocument() const button = screen.getByRole('button') - expect(button).toHaveStyle(`background-color: ${COLORS.blue40}`) + expect(button).toHaveStyle(`background-color: ${COLORS.blue35}`) }) it('renders the button as disabled', () => { diff --git a/app/src/molecules/FileUpload/index.tsx b/app/src/molecules/FileUpload/index.tsx new file mode 100644 index 00000000000..5e0fa7b0017 --- /dev/null +++ b/app/src/molecules/FileUpload/index.tsx @@ -0,0 +1,60 @@ +import * as React from 'react' +import { css } from 'styled-components' + +import { + ALIGN_CENTER, + BORDERS, + Btn, + COLORS, + DIRECTION_COLUMN, + Flex, + Icon, + JUSTIFY_SPACE_BETWEEN, + SPACING, + StyledText, +} from '@opentrons/components' + +const FILE_UPLOAD_STYLE = css` +&:hover > svg { + background: ${COLORS.black90}${COLORS.opacity20HexCode}; +} +&:active > svg { + background: ${COLORS.black90}${COLORS.opacity20HexCode}}; +} +` + +interface FileUploadProps { + file: File + fileError: string | null + handleClick: () => unknown +} + +export function FileUpload({ + file, + fileError, + handleClick, +}: FileUploadProps): JSX.Element { + return ( + + + + {file.name} + + + + {fileError != null ? ( + + {fileError} + + ) : null} + + ) +} diff --git a/app/src/molecules/MiniCard/__tests__/MiniCard.test.tsx b/app/src/molecules/MiniCard/__tests__/MiniCard.test.tsx index 536f8dc0b37..6a7c3efd034 100644 --- a/app/src/molecules/MiniCard/__tests__/MiniCard.test.tsx +++ b/app/src/molecules/MiniCard/__tests__/MiniCard.test.tsx @@ -25,8 +25,8 @@ describe('MiniCard', () => { it('renders the correct style unselectedOptionStyles', () => { render(props) const miniCard = screen.getByText('mock mini card') - expect(miniCard).toHaveStyle(`background-color: ${COLORS.grey10}`) - expect(miniCard).toHaveStyle(`border: 1px solid ${COLORS.grey35}`) + expect(miniCard).toHaveStyle(`background-color: ${COLORS.white}`) + expect(miniCard).toHaveStyle(`border: 1px solid ${COLORS.grey30}`) expect(miniCard).toHaveStyle(`border-radius: ${BORDERS.borderRadius8}`) expect(miniCard).toHaveStyle(`padding: ${SPACING.spacing8}`) expect(miniCard).toHaveStyle(`width: 100%`) diff --git a/app/src/molecules/ModuleIcon/__tests__/ModuleIcon.test.tsx b/app/src/molecules/ModuleIcon/__tests__/ModuleIcon.test.tsx index aa570078eb8..49e0ed4c118 100644 --- a/app/src/molecules/ModuleIcon/__tests__/ModuleIcon.test.tsx +++ b/app/src/molecules/ModuleIcon/__tests__/ModuleIcon.test.tsx @@ -58,7 +58,7 @@ describe('ModuleIcon', () => { it('renders SharedIcon with correct style', () => { render(props) const module = screen.getByTestId('ModuleIcon_ot-temperature-v2') - expect(module).toHaveStyle(`color: ${COLORS.black90}`) + expect(module).toHaveStyle(`color: ${COLORS.grey60}`) expect(module).toHaveStyle(`height: ${SPACING.spacing16}`) expect(module).toHaveStyle(`width: ${SPACING.spacing16}`) expect(module).toHaveStyle(`margin-left: ${SPACING.spacing2}`) diff --git a/app/src/molecules/ReleaseNotes/index.tsx b/app/src/molecules/ReleaseNotes/index.tsx index 57eb22b04c6..1b3e1821bd8 100644 --- a/app/src/molecules/ReleaseNotes/index.tsx +++ b/app/src/molecules/ReleaseNotes/index.tsx @@ -1,35 +1,37 @@ import * as React from 'react' -import remark from 'remark' -import reactRenderer from 'remark-react' +import Markdown from 'react-markdown' + import { StyledText } from '@opentrons/components' +import { useIsOEMMode } from '../../resources/robot-settings/hooks' + import styles from './styles.module.css' + export interface ReleaseNotesProps { source?: string | null } -// ToDo (kk:09/22/2023) This component should be updated in the future -// since the package we use hasn't been updated more than 2 years. -// Also the creator recommends users to replace remark-react with rehype-react. -const renderer = remark().use(reactRenderer, { - remarkReactComponents: { - div: React.Fragment, - h2: HeaderText, - ul: React.Fragment, - li: ParagraphText, - p: ParagraphText, - a: ExternalLink, - }, -}) - const DEFAULT_RELEASE_NOTES = 'We recommend upgrading to the latest version.' export function ReleaseNotes(props: ReleaseNotesProps): JSX.Element { const { source } = props + const isOEMMode = useIsOEMMode() + return (
- {source != null ? ( - renderer.processSync(source).contents + {source != null && !isOEMMode ? ( + + {source} + ) : (

{DEFAULT_RELEASE_NOTES}

)} @@ -48,3 +50,11 @@ function ParagraphText(props: JSX.IntrinsicAttributes): JSX.Element { function HeaderText(props: JSX.IntrinsicAttributes): JSX.Element { return } + +function ListItemText(props: JSX.IntrinsicAttributes): JSX.Element { + return +} + +function UnnumberedListText(props: JSX.IntrinsicAttributes): JSX.Element { + return +} diff --git a/app/src/molecules/UploadInput/index.tsx b/app/src/molecules/UploadInput/index.tsx index ea98b4735f3..45982e20ff2 100644 --- a/app/src/molecules/UploadInput/index.tsx +++ b/app/src/molecules/UploadInput/index.tsx @@ -45,11 +45,19 @@ const StyledInput = styled.input` export interface UploadInputProps { onUpload: (file: File) => unknown onClick?: () => void + uploadButtonText?: string uploadText?: string | JSX.Element dragAndDropText?: string | JSX.Element } export function UploadInput(props: UploadInputProps): JSX.Element | null { + const { + dragAndDropText, + onClick, + onUpload, + uploadButtonText, + uploadText, + } = props const { t } = useTranslation('protocol_info') const fileInput = React.useRef(null) @@ -60,7 +68,7 @@ export function UploadInput(props: UploadInputProps): JSX.Element | null { const handleDrop: React.DragEventHandler = e => { e.preventDefault() e.stopPropagation() - Array.from(e.dataTransfer.files).forEach(f => props.onUpload(f)) + Array.from(e.dataTransfer.files).forEach(f => onUpload(f)) setIsFileOverDropZone(false) } const handleDragEnter: React.DragEventHandler = e => { @@ -81,11 +89,11 @@ export function UploadInput(props: UploadInputProps): JSX.Element | null { } const handleClick: React.MouseEventHandler = _event => { - props.onClick != null ? props.onClick() : fileInput.current?.click() + onClick != null ? onClick() : fileInput.current?.click() } const onChange: React.ChangeEventHandler = event => { - ;[...(event.target.files ?? [])].forEach(f => props.onUpload(f)) + ;[...(event.target.files ?? [])].forEach(f => onUpload(f)) if ('value' in event.currentTarget) event.currentTarget.value = '' } @@ -97,18 +105,20 @@ export function UploadInput(props: UploadInputProps): JSX.Element | null { alignItems={ALIGN_CENTER} gridGap={SPACING.spacing24} > - - {props.uploadText} - + {uploadText != null ? ( + + {uploadText} + + ) : null} - {t('upload')} + {uploadButtonText ?? t('upload')} - {props.dragAndDropText} + {dragAndDropText} () const trackEvent = useTrackEvent() @@ -54,7 +54,7 @@ export function OverridePathToPython(): JSX.Element { {t('override_path_to_python')} - {t('opentrons_app_will_use_interpreter')} + {t('branded:opentrons_app_will_use_interpreter')} () const isLabwareOffsetCodeSnippetsOn = useSelector( getIsLabwareOffsetCodeSnippetsOn @@ -47,7 +47,7 @@ export function ShowLabwareOffsetSnippets(): JSX.Element { {t('show_labware_offset_snippets')} - {t('show_labware_offset_snippets_description')} + {t('branded:show_labware_offset_snippets_description')} { render() screen.getByText('Show Labware Offset data code snippets') screen.getByText( - 'Only for users who need to apply Labware Offset data outside of the Opentrons App. When enabled, code snippets for Jupyter Notebook and SSH are available during protocol setup.' + 'Only for users who need to apply labware offset data outside of the Opentrons App. When enabled, code snippets for Jupyter Notebook and SSH are available during protocol setup.' ) screen.getByRole('switch', { name: 'show_link_to_get_labware_offset_data' }) }) diff --git a/app/src/organisms/Alerts/AlertsModal.tsx b/app/src/organisms/Alerts/AlertsModal.tsx index 928d5762a0e..34b6f4c66c4 100644 --- a/app/src/organisms/Alerts/AlertsModal.tsx +++ b/app/src/organisms/Alerts/AlertsModal.tsx @@ -24,7 +24,7 @@ interface AlertsModalProps { export function AlertsModal({ toastIdRef }: AlertsModalProps): JSX.Element { const dispatch = useDispatch() const [showUpdateModal, setShowUpdateModal] = React.useState(false) - const { t } = useTranslation('app_settings') + const { t } = useTranslation(['app_settings', 'branded']) const { makeToast } = useToaster() const { removeActiveAppUpdateToast } = useRemoveActiveAppUpdateToast() @@ -54,10 +54,14 @@ export function AlertsModal({ toastIdRef }: AlertsModalProps): JSX.Element { // Only run this hook on app startup React.useEffect(() => { if (hasJustUpdated) { - makeToast(t('opentrons_app_successfully_updated'), SUCCESS_TOAST, { - closeButton: true, - disableTimeout: true, - }) + makeToast( + t('branded:opentrons_app_successfully_updated'), + SUCCESS_TOAST, + { + closeButton: true, + disableTimeout: true, + } + ) dispatch(toggleConfigValue('update.hasJustUpdated')) } }, []) @@ -65,7 +69,7 @@ export function AlertsModal({ toastIdRef }: AlertsModalProps): JSX.Element { React.useEffect(() => { if (createAppUpdateAvailableToast) { toastIdRef.current = makeToast( - t('opentrons_app_update_available_variation'), + t('branded:opentrons_app_update_available_variation'), WARNING_TOAST, { closeButton: true, diff --git a/app/src/organisms/AppSettings/ConnectRobotSlideout.tsx b/app/src/organisms/AppSettings/ConnectRobotSlideout.tsx index eaef9184985..1935cd33d78 100644 --- a/app/src/organisms/AppSettings/ConnectRobotSlideout.tsx +++ b/app/src/organisms/AppSettings/ConnectRobotSlideout.tsx @@ -43,7 +43,7 @@ export function ConnectRobotSlideout({ const [mostRecentDiscovered, setMostRecentDiscovered] = React.useState< boolean | null >(null) - const { t } = useTranslation(['app_settings', 'shared']) + const { t } = useTranslation(['app_settings', 'shared', 'branded']) const dispatch = useDispatch() const refreshDiscovery = (): unknown => dispatch(startDiscovery()) const isScanning = useSelector(getScanning) @@ -81,7 +81,7 @@ export function ConnectRobotSlideout({ {t('ip_description_first')} - {t('ip_description_second')} + {t('branded:ip_description_second')} - {t('restore_description')} + {t('branded:restore_description')} - {t('learn_uninstalling')} + {t('branded:learn_uninstalling')} - {t('previous_releases')} + {t('branded:previous_releases')} diff --git a/app/src/organisms/CalibrateTipLength/AskForCalibrationBlockModal.tsx b/app/src/organisms/CalibrateTipLength/AskForCalibrationBlockModal.tsx index 41a21ff0cba..c767cb4ee39 100644 --- a/app/src/organisms/CalibrateTipLength/AskForCalibrationBlockModal.tsx +++ b/app/src/organisms/CalibrateTipLength/AskForCalibrationBlockModal.tsx @@ -40,7 +40,7 @@ interface Props { } export function AskForCalibrationBlockModal(props: Props): JSX.Element { - const { t } = useTranslation(['robot_calibration', 'shared']) + const { t } = useTranslation(['robot_calibration', 'shared', 'branded']) const [rememberPreference, setRememberPreference] = React.useState( true ) @@ -77,7 +77,7 @@ export function AskForCalibrationBlockModal(props: Props): JSX.Element { , supportLink: ( diff --git a/app/src/organisms/CalibrationPanels/ChooseTipRack.tsx b/app/src/organisms/CalibrationPanels/ChooseTipRack.tsx index fed5ab02911..08e0b22e51b 100644 --- a/app/src/organisms/CalibrationPanels/ChooseTipRack.tsx +++ b/app/src/organisms/CalibrationPanels/ChooseTipRack.tsx @@ -75,7 +75,7 @@ export function ChooseTipRack(props: ChooseTipRackProps): JSX.Element { robotName, defaultTipracks, } = props - const { t } = useTranslation(['robot_calibration', 'shared']) + const { t } = useTranslation(['robot_calibration', 'shared', 'branded']) const pipSerial = usePipettesQuery( {}, { @@ -143,7 +143,7 @@ export function ChooseTipRack(props: ChooseTipRackProps): JSX.Element { customTipRacks.length > 0 ? [ { - label: t('opentrons'), + label: t('branded:opentrons_tip_rack_name'), options: opentronsTipRacksOptions, }, { @@ -233,14 +233,14 @@ export function ChooseTipRack(props: ChooseTipRackProps): JSX.Element { - {t('opentrons_tip_racks_recommended')} + {t('branded:opentrons_tip_racks_recommended')} - {t('calibration_on_opentrons_tips_is_important')} + {t('branded:calibration_on_opentrons_tips_is_important')} diff --git a/app/src/organisms/ChildNavigation/ChildNavigation.stories.tsx b/app/src/organisms/ChildNavigation/ChildNavigation.stories.tsx index da15b3af90e..cddbb2cd7a3 100644 --- a/app/src/organisms/ChildNavigation/ChildNavigation.stories.tsx +++ b/app/src/organisms/ChildNavigation/ChildNavigation.stories.tsx @@ -15,6 +15,13 @@ const Template: Story> = args => ( export const Default = Template.bind({}) Default.args = { header: 'Header', + onClickBack: () => {}, +} + +export const TitleNoBackButton = Template.bind({}) +TitleNoBackButton.args = { + header: 'Header', + onClickBack: undefined, } export const TitleWithNormalSmallButton = Template.bind({}) @@ -22,6 +29,16 @@ TitleWithNormalSmallButton.args = { header: 'Header', buttonText: 'ButtonText', onClickButton: () => {}, + onClickBack: () => {}, +} + +export const TitleWithNormalSmallButtonDisabled = Template.bind({}) +TitleWithNormalSmallButtonDisabled.args = { + header: 'Header', + buttonText: 'ButtonText', + onClickButton: () => {}, + onClickBack: () => {}, + buttonIsDisabled: true, } export const TitleWithLinkButton = Template.bind({}) @@ -32,6 +49,7 @@ TitleWithLinkButton.args = { iconName: 'information', iconPlacement: 'startIcon', onClickButton: () => {}, + onClickBack: () => {}, } export const TitleWithTwoButtons = Template.bind({}) @@ -47,4 +65,5 @@ TitleWithTwoButtons.args = { buttonText: 'ButtonText', onClickButton: () => {}, secondaryButtonProps, + onClickBack: () => {}, } diff --git a/app/src/organisms/ChildNavigation/__tests__/ChildNavigation.test.tsx b/app/src/organisms/ChildNavigation/__tests__/ChildNavigation.test.tsx index 8f53b640187..8e2a1c7ec0e 100644 --- a/app/src/organisms/ChildNavigation/__tests__/ChildNavigation.test.tsx +++ b/app/src/organisms/ChildNavigation/__tests__/ChildNavigation.test.tsx @@ -72,4 +72,26 @@ describe('ChildNavigation', () => { fireEvent.click(secondaryButton) expect(mockOnClickSecondaryButton).toHaveBeenCalled() }) + it.fails( + 'should not render back button if onClickBack does not exist', + () => { + props = { + ...props, + onClickBack: undefined, + } + render(props) + screen.getByTestId('ChildNavigation_Back_Button') + } + ) + it('should render button as disabled', () => { + props = { + ...props, + buttonText: 'mock button', + onClickButton: mockOnClickButton, + buttonIsDisabled: true, + } + render(props) + const button = screen.getByTestId('ChildNavigation_Primary_Button') + expect(button).toBeDisabled() + }) }) diff --git a/app/src/organisms/ChildNavigation/index.tsx b/app/src/organisms/ChildNavigation/index.tsx index afe3c1f7508..d45e79280f8 100644 --- a/app/src/organisms/ChildNavigation/index.tsx +++ b/app/src/organisms/ChildNavigation/index.tsx @@ -20,20 +20,21 @@ import { ODD_FOCUS_VISIBLE } from '../../atoms/buttons/constants' import { SmallButton } from '../../atoms/buttons' import { InlineNotification } from '../../atoms/InlineNotification' -import type { IconName } from '@opentrons/components' +import type { IconName, StyleProps } from '@opentrons/components' import type { InlineNotificationProps } from '../../atoms/InlineNotification' import type { IconPlacement, SmallButtonTypes, } from '../../atoms/buttons/SmallButton' -interface ChildNavigationProps { +interface ChildNavigationProps extends StyleProps { header: string - onClickBack: React.MouseEventHandler + onClickBack?: React.MouseEventHandler buttonText?: React.ReactNode inlineNotification?: InlineNotificationProps onClickButton?: React.MouseEventHandler buttonType?: SmallButtonTypes + buttonIsDisabled?: boolean iconName?: IconName iconPlacement?: IconPlacement secondaryButtonProps?: React.ComponentProps @@ -49,6 +50,8 @@ export function ChildNavigation({ iconName, iconPlacement, secondaryButtonProps, + buttonIsDisabled, + ...styleProps }: ChildNavigationProps): JSX.Element { return ( - - - + {onClickBack != null ? ( + + + + ) : null} {header} @@ -77,7 +83,10 @@ export function ChildNavigation({ {onClickButton != null && buttonText != null ? ( {secondaryButtonProps != null ? ( - + ) : null} ) : null} diff --git a/app/src/organisms/ChooseProtocolSlideout/__tests__/ChooseProtocolSlideout.test.tsx b/app/src/organisms/ChooseProtocolSlideout/__tests__/ChooseProtocolSlideout.test.tsx index 11583264b3e..7973023d184 100644 --- a/app/src/organisms/ChooseProtocolSlideout/__tests__/ChooseProtocolSlideout.test.tsx +++ b/app/src/organisms/ChooseProtocolSlideout/__tests__/ChooseProtocolSlideout.test.tsx @@ -3,15 +3,21 @@ import { vi, it, describe, expect, beforeEach } from 'vitest' import { StaticRouter } from 'react-router-dom' import { fireEvent, screen } from '@testing-library/react' +import { simpleAnalysisFileFixture } from '@opentrons/api-client' +import { OT2_ROBOT_TYPE } from '@opentrons/shared-data' import { renderWithProviders } from '../../../__testing-utils__' import { i18n } from '../../../i18n' import { getStoredProtocols } from '../../../redux/protocol-storage' import { mockConnectableRobot } from '../../../redux/discovery/__fixtures__' -import { storedProtocolData as storedProtocolDataFixture } from '../../../redux/protocol-storage/__fixtures__' +import { + storedProtocolData as storedProtocolDataFixture, + storedProtocolDataWithoutRunTimeParameters, +} from '../../../redux/protocol-storage/__fixtures__' import { useTrackCreateProtocolRunEvent } from '../../../organisms/Devices/hooks' import { useCreateRunFromProtocol } from '../../ChooseRobotToRunProtocolSlideout/useCreateRunFromProtocol' import { ChooseProtocolSlideout } from '../' import { useNotifyService } from '../../../resources/useNotifyService' +import type { ProtocolAnalysisOutput } from '@opentrons/shared-data' vi.mock('../../ChooseRobotToRunProtocolSlideout/useCreateRunFromProtocol') vi.mock('../../../redux/protocol-storage') @@ -30,6 +36,20 @@ const render = (props: React.ComponentProps) => { ) } +const modifiedSimpleAnalysisFileFixture = { + ...simpleAnalysisFileFixture, + robotType: OT2_ROBOT_TYPE, +} +const mockStoredProtocolDataFixture = [ + { + ...storedProtocolDataFixture, + mostRecentAnalysis: ({ + ...modifiedSimpleAnalysisFileFixture, + runTimeParameters: [], + } as any) as ProtocolAnalysisOutput, + }, +] + describe('ChooseProtocolSlideout', () => { let mockCreateRunFromProtocol = vi.fn() let mockTrackCreateProtocolRunEvent = vi.fn() @@ -38,7 +58,7 @@ describe('ChooseProtocolSlideout', () => { mockTrackCreateProtocolRunEvent = vi.fn( () => new Promise(resolve => resolve({})) ) - vi.mocked(getStoredProtocols).mockReturnValue([storedProtocolDataFixture]) + vi.mocked(getStoredProtocols).mockReturnValue(mockStoredProtocolDataFixture) vi.mocked(useCreateRunFromProtocol).mockReturnValue({ createRunFromProtocolSource: mockCreateRunFromProtocol, reset: vi.fn(), @@ -86,34 +106,32 @@ describe('ChooseProtocolSlideout', () => { ).toBeInTheDocument() }) - // it('calls createRunFromProtocolSource if CTA clicked', () => { - // const protocolDataWithoutRunTimeParameter = { - // ...storedProtocolDataFixture, - // runTimeParameters: [], - // } - // vi.mocked(getStoredProtocols).mockReturnValue([ - // protocolDataWithoutRunTimeParameter, - // ]) - // render({ - // robot: mockConnectableRobot, - // onCloseClick: vi.fn(), - // showSlideout: true, - // }) - // const proceedButton = screen.getByRole('button', { - // name: 'Proceed to setup', - // }) - // fireEvent.click(proceedButton) - // expect(mockCreateRunFromProtocol).toHaveBeenCalledWith({ - // files: [expect.any(File)], - // protocolKey: storedProtocolDataFixture.protocolKey, - // }) - // expect(mockTrackCreateProtocolRunEvent).toHaveBeenCalled() - // }) + it('calls createRunFromProtocolSource if CTA clicked', () => { + const protocolDataWithoutRunTimeParameter = { + ...storedProtocolDataWithoutRunTimeParameters, + } + vi.mocked(getStoredProtocols).mockReturnValue([ + protocolDataWithoutRunTimeParameter, + ]) + render({ + robot: mockConnectableRobot, + onCloseClick: vi.fn(), + showSlideout: true, + }) + const proceedButton = screen.getByRole('button', { + name: 'Proceed to setup', + }) + fireEvent.click(proceedButton) + expect(mockCreateRunFromProtocol).toHaveBeenCalledWith({ + files: [expect.any(File)], + protocolKey: storedProtocolDataFixture.protocolKey, + }) + expect(mockTrackCreateProtocolRunEvent).toHaveBeenCalled() + }) it('move to the second slideout if CTA clicked', () => { const protocolDataWithoutRunTimeParameter = { ...storedProtocolDataFixture, - runTimeParameters: [], } vi.mocked(getStoredProtocols).mockReturnValue([ protocolDataWithoutRunTimeParameter, @@ -132,7 +150,7 @@ describe('ChooseProtocolSlideout', () => { screen.getByText('Restore default values') }) - // ToDo (kk:04/08) update test for RTP + // ToDo (kk:04/18/2024) I will update test for RTP /* it('renders error state when there is a run creation error', () => { vi.mocked(useCreateRunFromProtocol).mockReturnValue({ diff --git a/app/src/organisms/ChooseProtocolSlideout/index.tsx b/app/src/organisms/ChooseProtocolSlideout/index.tsx index fd9085e07cb..04d117dd41b 100644 --- a/app/src/organisms/ChooseProtocolSlideout/index.tsx +++ b/app/src/organisms/ChooseProtocolSlideout/index.tsx @@ -105,7 +105,6 @@ export function ChooseProtocolSlideoutComponent( const runTimeParametersFromAnalysis = selectedProtocol?.mostRecentAnalysis?.runTimeParameters ?? [] - console.log('runTimeParametersFromAnalysis', runTimeParametersFromAnalysis) const hasRunTimeParameters = runTimeParametersFromAnalysis.length > 0 @@ -222,7 +221,6 @@ export function ChooseProtocolSlideoutComponent( setRunTimeParametersOverrides(clone) }} title={runtimeParam.displayName} - caption={runtimeParam.description} width="100%" dropdownType="neutral" /> @@ -253,7 +251,7 @@ export function ChooseProtocolSlideoutComponent( key={runtimeParam.variableName} type="number" units={runtimeParam.suffix} - placeholder={value.toString()} + placeholder={runtimeParam.default.toString()} value={value} title={runtimeParam.displayName} tooltipText={runtimeParam.description} @@ -313,14 +311,14 @@ export function ChooseProtocolSlideoutComponent( }} height="0.813rem" label={ - runtimeParam.value + Boolean(runtimeParam.value) ? t('protocol_details:on') : t('protocol_details:off') } paddingTop={SPACING.spacing2} // manual alignment of SVG with value label /> - {runtimeParam.value + {Boolean(runtimeParam.value) ? t('protocol_details:on') : t('protocol_details:off')} @@ -333,6 +331,15 @@ export function ChooseProtocolSlideoutComponent( } }) ?? null + const resetRunTimeParameters = (): void => { + setRunTimeParametersOverrides( + runTimeParametersOverrides?.map(parameter => ({ + ...parameter, + value: parameter.default, + })) + ) + } + const pageTwoBody = ( @@ -341,13 +348,7 @@ export function ChooseProtocolSlideoutComponent( css={ isRestoreDefaultsLinkEnabled ? ENABLED_LINK_CSS : DISABLED_LINK_CSS } - onClick={() => { - const clone = runTimeParametersOverrides.map(parameter => ({ - ...parameter, - value: parameter.default, - })) - setRunTimeParametersOverrides(clone) - }} + onClick={resetRunTimeParameters} paddingBottom={SPACING.spacing10} {...targetProps} > @@ -410,7 +411,11 @@ export function ChooseProtocolSlideoutComponent( return ( { + onCloseClick() + setCurrentPage(1) + resetRunTimeParameters() + }} currentStep={currentPage} maxSteps={hasRunTimeParameters ? 2 : 1} title={t('choose_protocol_to_run', { name })} @@ -456,7 +461,7 @@ export function ChooseProtocolSlideoutComponent( setSelectedProtocol(storedProtocol) } }} - robotName={robot.name} + robot={robot} {...{ selectedProtocol, runCreationError, runCreationErrorCode }} /> ) : ( @@ -478,7 +483,7 @@ interface StoredProtocolListProps { handleSelectProtocol: (storedProtocol: StoredProtocolData | null) => void runCreationError: string | null runCreationErrorCode: number | null - robotName: string + robot: Robot } function StoredProtocolList(props: StoredProtocolListProps): JSX.Element { @@ -487,11 +492,13 @@ function StoredProtocolList(props: StoredProtocolListProps): JSX.Element { handleSelectProtocol, runCreationError, runCreationErrorCode, - robotName, + robot, } = props const { t } = useTranslation(['device_details', 'protocol_details', 'shared']) const storedProtocols = useSelector((state: State) => getStoredProtocols(state) + ).filter( + protocol => protocol.mostRecentAnalysis?.robotType === robot.robotModel ) React.useEffect(() => { handleSelectProtocol(first(storedProtocols) ?? null) @@ -519,19 +526,27 @@ function StoredProtocolList(props: StoredProtocolListProps): JSX.Element { onClick={() => handleSelectProtocol(storedProtocol)} > - - {!missingAnalysisData ? ( + {!missingAnalysisData ? ( + - ) : null} - + + ) : ( + + )} ), }} diff --git a/app/src/organisms/ChooseRobotSlideout/AvailableRobotOption.tsx b/app/src/organisms/ChooseRobotSlideout/AvailableRobotOption.tsx index c65e69ce163..148b9e30e35 100644 --- a/app/src/organisms/ChooseRobotSlideout/AvailableRobotOption.tsx +++ b/app/src/organisms/ChooseRobotSlideout/AvailableRobotOption.tsx @@ -53,7 +53,7 @@ export function AvailableRobotOption( registerRobotBusyStatus, } = props const { ip, local, name: robotName } = robot ?? {} - const { t } = useTranslation('protocol_list') + const { t } = useTranslation(['protocol_list', 'branded']) const dispatch = useDispatch() const robotModel = useSelector((state: State) => getRobotModelByName(state, robotName) @@ -160,7 +160,7 @@ export function AvailableRobotOption( > , }} diff --git a/app/src/organisms/ChooseRobotSlideout/__tests__/ChooseRobotSlideout.test.tsx b/app/src/organisms/ChooseRobotSlideout/__tests__/ChooseRobotSlideout.test.tsx index 18bdf233f75..19500166410 100644 --- a/app/src/organisms/ChooseRobotSlideout/__tests__/ChooseRobotSlideout.test.tsx +++ b/app/src/organisms/ChooseRobotSlideout/__tests__/ChooseRobotSlideout.test.tsx @@ -3,6 +3,7 @@ import { vi, it, describe, expect, beforeEach } from 'vitest' import { StaticRouter } from 'react-router-dom' import { fireEvent, screen } from '@testing-library/react' +import { OT2_ROBOT_TYPE } from '@opentrons/shared-data' import { renderWithProviders } from '../../../__testing-utils__' import { i18n } from '../../../i18n' @@ -22,7 +23,7 @@ import { useFeatureFlag } from '../../../redux/config' import { getNetworkInterfaces } from '../../../redux/networking' import { ChooseRobotSlideout } from '..' import { useNotifyService } from '../../../resources/useNotifyService' -import { OT2_ROBOT_TYPE, RunTimeParameter } from '@opentrons/shared-data' +import type { RunTimeParameter } from '@opentrons/shared-data' vi.mock('../../../redux/discovery') vi.mock('../../../redux/robot-update') @@ -226,14 +227,14 @@ describe('ChooseRobotSlideout', () => { }) screen.getByText(param.displayName) - if (param.type === 'bool' || 'choices' in param) { + if (param.type === 'bool') { screen.getByText(param.description) - } else { - if (param.type === 'int') { - screen.getByText(`${param.min}-${param.max}`) - } else { - screen.getByText(`${param.min.toFixed(1)}-${param.max.toFixed(1)}`) - } + } + if (param.type === 'int') { + screen.getByText(`${param.min}-${param.max}`) + } + if (param.type === 'float') { + screen.getByText(`${param.min.toFixed(1)}-${param.max.toFixed(1)}`) } }) }) @@ -295,4 +296,18 @@ describe('ChooseRobotSlideout', () => { ip: 'otherIp', }) }) + + it('sets selected robot to null if no available robots', () => { + vi.mocked(getConnectableRobots).mockReturnValue([]) + render({ + onCloseClick: vi.fn(), + isExpanded: true, + isSelectedRobotOnDifferentSoftwareVersion: false, + selectedRobot: null, + setSelectedRobot: mockSetSelectedRobot, + title: 'choose robot slideout title', + robotType: OT2_ROBOT_TYPE, + }) + expect(mockSetSelectedRobot).toBeCalledWith(null) + }) }) diff --git a/app/src/organisms/ChooseRobotSlideout/index.tsx b/app/src/organisms/ChooseRobotSlideout/index.tsx index d19a62a514d..fd77056db76 100644 --- a/app/src/organisms/ChooseRobotSlideout/index.tsx +++ b/app/src/organisms/ChooseRobotSlideout/index.tsx @@ -113,6 +113,7 @@ interface ChooseRobotSlideoutProps showIdleOnly?: boolean multiSlideout?: { currentPage: number } | null setHasParamError?: (isError: boolean) => void + resetRunTimeParameters?: () => void } export function ChooseRobotSlideout( @@ -139,6 +140,7 @@ export function ChooseRobotSlideout( runTimeParametersOverrides, setRunTimeParametersOverrides, setHasParamError, + resetRunTimeParameters, } = props const dispatch = useDispatch() @@ -184,18 +186,27 @@ export function ChooseRobotSlideout( {} ) + const reducerAvailableRobots = healthyReachableRobots.filter(robot => + showIdleOnly ? !robotBusyStatusByName[robot.name] : robot + ) const reducerBusyCount = healthyReachableRobots.filter( robot => robotBusyStatusByName[robot.name] ).length // this useEffect sets the default selection to the first robot in the list. state is managed by the caller React.useEffect(() => { - if (selectedRobot == null && healthyReachableRobots.length > 0) { - setSelectedRobot(healthyReachableRobots[0]) - } else if (healthyReachableRobots.length === 0) { + if ( + (selectedRobot == null || + !reducerAvailableRobots.some( + robot => robot.name === selectedRobot.name + )) && + reducerAvailableRobots.length > 0 + ) { + setSelectedRobot(reducerAvailableRobots[0]) + } else if (reducerAvailableRobots.length === 0) { setSelectedRobot(null) } - }, [healthyReachableRobots, selectedRobot, setSelectedRobot]) + }, [reducerAvailableRobots, selectedRobot, setSelectedRobot]) const unavailableCount = unhealthyReachableRobots.length + unreachableRobots.length @@ -363,9 +374,9 @@ export function ChooseRobotSlideout( } }} title={runtimeParam.displayName} - caption={runtimeParam.description} width="100%" dropdownType="neutral" + tooltipText={runtimeParam.description} /> ) } else if (runtimeParam.type === 'int' || runtimeParam.type === 'float') { @@ -394,7 +405,7 @@ export function ChooseRobotSlideout( key={runtimeParam.variableName} type="number" units={runtimeParam.suffix} - placeholder={value.toString()} + placeholder={runtimeParam.default.toString()} value={value} title={runtimeParam.displayName} tooltipText={runtimeParam.description} @@ -498,15 +509,7 @@ export function ChooseRobotSlideout( ? ENABLED_LINK_CSS : DISABLED_LINK_CSS } - onClick={() => { - const clone = runTimeParametersOverrides.map(parameter => ({ - ...parameter, - value: parameter.default, - })) - if (setRunTimeParametersOverrides != null) { - setRunTimeParametersOverrides(clone) - } - }} + onClick={() => resetRunTimeParameters?.()} paddingBottom={SPACING.spacing10} {...targetProps} > diff --git a/app/src/organisms/ChooseRobotToRunProtocolSlideout/__tests__/ChooseRobotToRunProtocolSlideout.test.tsx b/app/src/organisms/ChooseRobotToRunProtocolSlideout/__tests__/ChooseRobotToRunProtocolSlideout.test.tsx index b7d2b32cb75..9ac6e0232ea 100644 --- a/app/src/organisms/ChooseRobotToRunProtocolSlideout/__tests__/ChooseRobotToRunProtocolSlideout.test.tsx +++ b/app/src/organisms/ChooseRobotToRunProtocolSlideout/__tests__/ChooseRobotToRunProtocolSlideout.test.tsx @@ -390,4 +390,31 @@ describe('ChooseRobotToRunProtocolSlideout', () => { {} ) }) + + it('disables proceed button if no available robots', () => { + vi.mocked(getConnectableRobots).mockReturnValue([]) + render({ + storedProtocolData: storedProtocolDataFixture, + onCloseClick: vi.fn(), + showSlideout: true, + }) + const proceedButton = screen.getByRole('button', { + name: 'Continue to parameters', + }) + expect(proceedButton).toBeDisabled() + }) + + it('renders labware offset data selection and learn more button launches help modal', () => { + render({ + storedProtocolData: storedProtocolDataFixture, + onCloseClick: vi.fn(), + showSlideout: true, + }) + screen.getByText('No offset data available') + const learnMoreLink = screen.getByText('Learn more') + fireEvent.click(learnMoreLink) + screen.getByText( + 'Labware offset data references previous protocol run labware locations to save you time. If all the labware in this protocol have been checked in previous runs, that data will be applied to this run.' + ) + }) }) diff --git a/app/src/organisms/ChooseRobotToRunProtocolSlideout/index.tsx b/app/src/organisms/ChooseRobotToRunProtocolSlideout/index.tsx index 8ef332adaa3..5dd3278bdfe 100644 --- a/app/src/organisms/ChooseRobotToRunProtocolSlideout/index.tsx +++ b/app/src/organisms/ChooseRobotToRunProtocolSlideout/index.tsx @@ -132,6 +132,8 @@ export function ChooseRobotToRunProtocolSlideoutComponent( 'downgrade', ].includes(autoUpdateAction) + const hasRunTimeParameters = runTimeParameters.length > 0 + if ( protocolKey == null || srcFileNames == null || @@ -156,7 +158,7 @@ export function ChooseRobotToRunProtocolSlideoutComponent( ? mostRecentAnalysis?.robotType ?? null : null - const SinglePageButtonWithoutFF = ( + const singlePageButton = ( ) - const hasRunTimeParameters = runTimeParameters.length > 0 + const offsetsComponent = ( + + ) + + const resetRunTimeParameters = (): void => { + setRunTimeParametersOverrides( + runTimeParametersOverrides?.map(parameter => ({ + ...parameter, + value: parameter.default, + })) + ) + } return ( { + onCloseClick() + resetRunTimeParameters() + setCurrentPage(1) + setSelectedRobot(null) + }} title={ hasRunTimeParameters && currentPage === 2 ? t('select_parameters_for_robot', { @@ -200,14 +225,7 @@ export function ChooseRobotToRunProtocolSlideoutComponent( {hasRunTimeParameters ? ( currentPage === 1 ? ( <> - + {offsetsComponent} setCurrentPage(2)} width="100%" @@ -239,7 +257,10 @@ export function ChooseRobotToRunProtocolSlideoutComponent( ) ) : ( - SinglePageButtonWithoutFF + <> + {offsetsComponent} + {singlePageButton} + )} } @@ -250,8 +271,9 @@ export function ChooseRobotToRunProtocolSlideoutComponent( reset={resetCreateRun} runCreationError={runCreationError} runCreationErrorCode={runCreationErrorCode} - showIdleOnly={true} + showIdleOnly setHasParamError={setHasParamError} + resetRunTimeParameters={resetRunTimeParameters} /> ) } diff --git a/app/src/organisms/CommandText/LoadCommandText.tsx b/app/src/organisms/CommandText/LoadCommandText.tsx index 62ce7cf1fd5..8dd2f8e64d1 100644 --- a/app/src/organisms/CommandText/LoadCommandText.tsx +++ b/app/src/organisms/CommandText/LoadCommandText.tsx @@ -131,7 +131,9 @@ export const LoadCommandText = ({ return null } } else { - const labware = command.result?.definition.metadata.displayName + const labware = + command.result?.definition.metadata.displayName ?? + command.params.displayName return command.params.location === 'offDeck' ? t('load_labware_info_protocol_setup_off_deck', { labware }) : t('load_labware_info_protocol_setup_no_module', { diff --git a/app/src/organisms/ConfigurePipette/ConfigFormResetButton.tsx b/app/src/organisms/ConfigurePipette/ConfigFormResetButton.tsx index d97524f1e59..32ac241955d 100644 --- a/app/src/organisms/ConfigurePipette/ConfigFormResetButton.tsx +++ b/app/src/organisms/ConfigurePipette/ConfigFormResetButton.tsx @@ -17,13 +17,13 @@ export interface ButtonProps { export function ConfigFormResetButton(props: ButtonProps): JSX.Element { const { onClick, disabled } = props - const { t } = useTranslation(['shared', 'device_details']) + const { t } = useTranslation(['shared', 'branded']) return ( void @@ -52,6 +66,12 @@ interface AddFixtureModalProps { providedFixtureOptions?: CutoutFixtureId[] isOnDevice?: boolean } +type OptionStage = + | 'modulesOrFixtures' + | 'fixtureOptions' + | 'moduleOptions' + | 'wasteChuteOptions' + | 'providedOptions' export function AddFixtureModal({ cutoutId, @@ -62,9 +82,26 @@ export function AddFixtureModal({ }: AddFixtureModalProps): JSX.Element { const { t } = useTranslation(['device_details', 'shared']) const { updateDeckConfiguration } = useUpdateDeckConfigurationMutation() - const deckConfig = useDeckConfigurationQuery()?.data ?? [] - const [showWasteChuteOptions, setShowWasteChuteOptions] = React.useState( - false + const { data: modulesData } = useModulesQuery() + const deckConfig = useNotifyDeckConfigurationQuery()?.data ?? [] + const unconfiguredMods = + modulesData?.data.filter( + attachedMod => + !deckConfig.some( + ({ opentronsModuleSerialNumber }) => + attachedMod.serialNumber === opentronsModuleSerialNumber + ) + ) ?? [] + + let initialStage: OptionStage = SINGLE_CENTER_CUTOUTS.includes(cutoutId) // only mag block (a module) can be configured in column 2 + ? 'moduleOptions' + : 'modulesOrFixtures' + if (providedFixtureOptions != null) { + // only show provided options if given as props + initialStage = 'providedOptions' + } + const [optionStage, setOptionStage] = React.useState( + initialStage ) const modalHeader: ModalHeaderBaseProps = { @@ -72,75 +109,232 @@ export function AddFixtureModal({ slotName: getCutoutDisplayName(cutoutId), }), hasExitIcon: providedFixtureOptions == null, - onClick: () => setShowAddFixtureModal(false), + onClick: () => { + setShowAddFixtureModal(false) + }, } const modalProps: LegacyModalProps = { title: t('add_to_slot', { slotName: getCutoutDisplayName(cutoutId), }), - onClose: () => setShowAddFixtureModal(false), + onClose: () => { + setShowAddFixtureModal(false) + }, closeOnOutsideClick: true, childrenPadding: SPACING.spacing24, width: '26.75rem', } - const availableFixtures: CutoutFixtureId[] = [TRASH_BIN_ADAPTER_FIXTURE] - if (STAGING_AREA_CUTOUTS.includes(cutoutId)) { - availableFixtures.push(STAGING_AREA_RIGHT_SLOT_FIXTURE) + let availableOptions: CutoutConfig[][] = [] + + if (providedFixtureOptions != null) { + availableOptions = providedFixtureOptions?.map(o => [ + { + cutoutId, + cutoutFixtureId: o, + opentronsModuleSerialNumber: undefined, + }, + ]) + } else if (optionStage === 'fixtureOptions') { + if ( + SINGLE_RIGHT_CUTOUTS.includes(cutoutId) || + SINGLE_LEFT_CUTOUTS.includes(cutoutId) + ) { + availableOptions = [ + ...availableOptions, + [ + { + cutoutId, + cutoutFixtureId: TRASH_BIN_ADAPTER_FIXTURE, + }, + ], + ] + } + if (STAGING_AREA_CUTOUTS.includes(cutoutId)) { + availableOptions = [ + ...availableOptions, + [ + { + cutoutId, + cutoutFixtureId: STAGING_AREA_RIGHT_SLOT_FIXTURE, + }, + ], + ] + } + } else if (optionStage === 'moduleOptions') { + availableOptions = [ + ...availableOptions, + [ + { + cutoutId, + cutoutFixtureId: MAGNETIC_BLOCK_V1_FIXTURE, + }, + ], + ] + if (SINGLE_RIGHT_CUTOUTS.includes(cutoutId)) { + availableOptions = [ + ...availableOptions, + [ + { + cutoutId, + cutoutFixtureId: STAGING_AREA_SLOT_WITH_MAGNETIC_BLOCK_V1_FIXTURE, + }, + ], + ] + } + if (unconfiguredMods.length > 0) { + if (THERMOCYCLER_MODULE_CUTOUTS.includes(cutoutId)) { + const unconfiguredTCs = unconfiguredMods + .filter(mod => mod.moduleModel === THERMOCYCLER_MODULE_V2) + .map(mod => [ + { + cutoutId: THERMOCYCLER_MODULE_CUTOUTS[0], + cutoutFixtureId: THERMOCYCLER_V2_REAR_FIXTURE, + opentronsModuleSerialNumber: mod.serialNumber, + }, + { + cutoutId: THERMOCYCLER_MODULE_CUTOUTS[1], + cutoutFixtureId: THERMOCYCLER_V2_FRONT_FIXTURE, + opentronsModuleSerialNumber: mod.serialNumber, + }, + ]) + availableOptions = [...availableOptions, ...unconfiguredTCs] + } + if ( + HEATER_SHAKER_CUTOUTS.includes(cutoutId) && + unconfiguredMods.some(m => m.moduleModel === HEATERSHAKER_MODULE_V1) + ) { + const unconfiguredHeaterShakers = unconfiguredMods + .filter(mod => mod.moduleModel === HEATERSHAKER_MODULE_V1) + .map(mod => [ + { + cutoutId, + cutoutFixtureId: HEATERSHAKER_MODULE_V1_FIXTURE, + opentronsModuleSerialNumber: mod.serialNumber, + }, + ]) + availableOptions = [...availableOptions, ...unconfiguredHeaterShakers] + } + if ( + TEMPERATURE_MODULE_CUTOUTS.includes(cutoutId) && + unconfiguredMods.some(m => m.moduleModel === TEMPERATURE_MODULE_V2) + ) { + const unconfiguredTemperatureModules = unconfiguredMods + .filter(mod => mod.moduleModel === TEMPERATURE_MODULE_V2) + .map(mod => [ + { + cutoutId, + cutoutFixtureId: TEMPERATURE_MODULE_V2_FIXTURE, + opentronsModuleSerialNumber: mod.serialNumber, + }, + ]) + availableOptions = [ + ...availableOptions, + ...unconfiguredTemperatureModules, + ] + } + } + } else if (optionStage === 'wasteChuteOptions') { + availableOptions = WASTE_CHUTE_FIXTURES.map(fixture => [ + { + cutoutId, + cutoutFixtureId: fixture, + }, + ]) } - const handleAddODD = (requiredFixtureId: CutoutFixtureId): void => { + let nextStageOptions = null + if (optionStage === 'modulesOrFixtures') { + nextStageOptions = ( + <> + {SINGLE_CENTER_CUTOUTS.includes(cutoutId) ? null : ( + { + setOptionStage('fixtureOptions') + }} + isOnDevice={isOnDevice} + /> + )} + { + setOptionStage('moduleOptions') + }} + isOnDevice={isOnDevice} + /> + + ) + } else if ( + optionStage === 'fixtureOptions' && + cutoutId === WASTE_CHUTE_CUTOUT + ) { + nextStageOptions = ( + <> + { + setOptionStage('wasteChuteOptions') + }} + isOnDevice={isOnDevice} + /> + + ) + } + + const handleAddODD = (addedCutoutConfigs: CutoutConfig[]): void => { if (setCurrentDeckConfig != null) setCurrentDeckConfig( (prevDeckConfig: DeckConfiguration): DeckConfiguration => - prevDeckConfig.map((fixture: CutoutConfig) => - fixture.cutoutId === cutoutId - ? { ...fixture, cutoutFixtureId: requiredFixtureId } - : fixture - ) + prevDeckConfig.map((fixture: CutoutConfig) => { + const replacementCutoutConfig = addedCutoutConfigs.find( + c => c.cutoutId === fixture.cutoutId + ) + return replacementCutoutConfig ?? fixture + }) ) setShowAddFixtureModal(false) } - const fixtureOptions = providedFixtureOptions ?? availableFixtures - const fixtureOptionsWithDisplayNames: Array< - [CutoutFixtureId | 'WASTE_CHUTE', string] - > = fixtureOptions.map(fixture => [fixture, getFixtureDisplayName(fixture)]) - - const showSelectWasteChuteOptions = - cutoutId === WASTE_CHUTE_CUTOUT && providedFixtureOptions == null - - const fixtureOptionsWithDisplayNamesAndGenericWasteChute = fixtureOptionsWithDisplayNames.concat( - showSelectWasteChuteOptions - ? [[GENERIC_WASTE_CHUTE_OPTION, t('waste_chute')]] - : [] - ) - - fixtureOptionsWithDisplayNamesAndGenericWasteChute.sort((a, b) => - a[1].localeCompare(b[1]) - ) - - const wasteChuteOptionsWithDisplayNames = WASTE_CHUTE_FIXTURES.map( - fixture => [fixture, getFixtureDisplayName(fixture)] - ).sort((a, b) => a[1].localeCompare(b[1])) as Array<[CutoutFixtureId, string]> - - const displayedFixtureOptions = showWasteChuteOptions - ? wasteChuteOptionsWithDisplayNames - : fixtureOptionsWithDisplayNamesAndGenericWasteChute - - const handleAddDesktop = (requiredFixtureId: CutoutFixtureId): void => { - const newDeckConfig = deckConfig.map(fixture => - fixture.cutoutId === cutoutId - ? { ...fixture, cutoutFixtureId: requiredFixtureId } - : fixture - ) + const handleAddDesktop = (addedCutoutConfigs: CutoutConfig[]): void => { + const newDeckConfig = deckConfig.map(fixture => { + const replacementCutoutConfig = addedCutoutConfigs.find( + c => c.cutoutId === fixture.cutoutId + ) + return replacementCutoutConfig ?? fixture + }) updateDeckConfiguration(newDeckConfig) setShowAddFixtureModal(false) } + const fixtureOptions = availableOptions.map(cutoutConfigs => ( + m.serialNumber === cutoutConfigs[0].opentronsModuleSerialNumber + )?.usbPort.port + )} + buttonText={t('add')} + onClickHandler={() => { + isOnDevice + ? handleAddODD(cutoutConfigs) + : handleAddDesktop(cutoutConfigs) + }} + isOnDevice={isOnDevice} + /> + )) + return ( <> {isOnDevice ? ( @@ -155,40 +349,8 @@ export function AddFixtureModal({ {t('add_to_slot_description')} - {displayedFixtureOptions.map( - ([cutoutFixtureOption, fixtureDisplayName]) => { - const onClickHandler = - cutoutFixtureOption === GENERIC_WASTE_CHUTE_OPTION - ? () => setShowWasteChuteOptions(true) - : () => handleAddODD(cutoutFixtureOption) - const buttonText = - cutoutFixtureOption === GENERIC_WASTE_CHUTE_OPTION - ? t('select_options') - : t('add') - - return ( - - - - {fixtureDisplayName} - - {buttonText} - - - ) - } - )} + {fixtureOptions} + {nextStageOptions} @@ -197,43 +359,15 @@ export function AddFixtureModal({ {t('add_fixture_description')} - {displayedFixtureOptions.map( - ([cutoutFixtureOption, fixtureDisplayName]) => { - const onClickHandler = - cutoutFixtureOption === GENERIC_WASTE_CHUTE_OPTION - ? () => setShowWasteChuteOptions(true) - : () => handleAddDesktop(cutoutFixtureOption) - const buttonText = - cutoutFixtureOption === GENERIC_WASTE_CHUTE_OPTION - ? t('select_options') - : t('add') - - return ( - - - - {fixtureDisplayName} - - - {buttonText} - - - - ) - } - )} + {fixtureOptions} + {nextStageOptions} - {showWasteChuteOptions ? ( + {optionStage === 'wasteChuteOptions' ? ( setShowWasteChuteOptions(false)} + onClick={() => { + setOptionStage('fixtureOptions') + }} aria-label="back" paddingX={SPACING.spacing16} marginTop={'1.44rem'} @@ -289,3 +423,41 @@ const GO_BACK_BUTTON_STYLE = css` opacity: 70%; } ` + +interface FixtureOptionProps { + onClickHandler: React.MouseEventHandler + optionName: string + buttonText: string + isOnDevice: boolean +} +export function FixtureOption(props: FixtureOptionProps): JSX.Element { + const { onClickHandler, optionName, buttonText, isOnDevice } = props + return isOnDevice ? ( + + + {props.optionName} + + {props.buttonText} + + ) : ( + + {optionName} + {buttonText} + + ) +} diff --git a/app/src/organisms/DeviceDetailsDeckConfiguration/DeckFixtureSetupInstructionsModal.tsx b/app/src/organisms/DeviceDetailsDeckConfiguration/DeckFixtureSetupInstructionsModal.tsx index 12d0f1d3967..9d622a4d4d5 100644 --- a/app/src/organisms/DeviceDetailsDeckConfiguration/DeckFixtureSetupInstructionsModal.tsx +++ b/app/src/organisms/DeviceDetailsDeckConfiguration/DeckFixtureSetupInstructionsModal.tsx @@ -32,7 +32,7 @@ export function DeckFixtureSetupInstructionsModal({ setShowSetupInstructionsModal, isOnDevice = false, }: DeckFixtureSetupInstructionsModalProps): JSX.Element { - const { i18n, t } = useTranslation(['device_details', 'shared']) + const { i18n, t } = useTranslation(['device_details', 'shared', 'branded']) const modalHeader: ModalHeaderBaseProps = { title: t('deck_fixture_setup_instructions'), iconName: 'information', @@ -62,7 +62,7 @@ export function DeckFixtureSetupInstructionsModal({ {t('deck_fixture_setup_modal_top_description')} - {t('deck_fixture_setup_modal_bottom_description')} + {t('branded:deck_fixture_setup_modal_bottom_description')} diff --git a/app/src/organisms/DeviceDetailsDeckConfiguration/__tests__/AddFixtureModal.test.tsx b/app/src/organisms/DeviceDetailsDeckConfiguration/__tests__/AddFixtureModal.test.tsx index 846c060dc27..de4538d3253 100644 --- a/app/src/organisms/DeviceDetailsDeckConfiguration/__tests__/AddFixtureModal.test.tsx +++ b/app/src/organisms/DeviceDetailsDeckConfiguration/__tests__/AddFixtureModal.test.tsx @@ -3,7 +3,7 @@ import { fireEvent, screen } from '@testing-library/react' import { describe, it, beforeEach, vi, expect, afterEach } from 'vitest' import { - useDeckConfigurationQuery, + useModulesQuery, useUpdateDeckConfigurationMutation, } from '@opentrons/react-api-client' import { @@ -14,11 +14,15 @@ import { import { renderWithProviders } from '../../../__testing-utils__' import { i18n } from '../../../i18n' import { AddFixtureModal } from '../AddFixtureModal' +import { useNotifyDeckConfigurationQuery } from '../../../resources/deck_configuration' import type { UseQueryResult } from 'react-query' import type { DeckConfiguration } from '@opentrons/shared-data' +import type { Modules } from '@opentrons/api-client' vi.mock('@opentrons/react-api-client') +vi.mock('../../../resources/deck_configuration') + const mockSetShowAddFixtureModal = vi.fn() const mockUpdateDeckConfiguration = vi.fn() const mockSetCurrentDeckConfig = vi.fn() @@ -42,26 +46,28 @@ describe('Touchscreen AddFixtureModal', () => { vi.mocked(useUpdateDeckConfigurationMutation).mockReturnValue({ updateDeckConfiguration: mockUpdateDeckConfiguration, } as any) - vi.mocked(useDeckConfigurationQuery).mockReturnValue(({ + vi.mocked(useNotifyDeckConfigurationQuery).mockReturnValue(({ data: [], } as unknown) as UseQueryResult) + vi.mocked(useModulesQuery).mockReturnValue(({ + data: { data: [] }, + } as unknown) as UseQueryResult) }) it('should render text and buttons', () => { render(props) screen.getByText('Add to slot D3') screen.getByText( - 'Choose a fixture below to add to your deck configuration. It will be referenced during protocol analysis.' + 'Choose an item below to add to your deck configuration. It will be referenced during protocol analysis.' ) - screen.getByText('Staging area slot') - screen.getByText('Trash bin') - screen.getByText('Waste chute') - expect(screen.getAllByText('Add').length).toBe(2) - expect(screen.getAllByText('Select options').length).toBe(1) + screen.getByText('Fixtures') + screen.getByText('Modules') + expect(screen.getAllByText('Select options').length).toBe(2) }) - it('should a mock function when tapping app button', () => { + it('should set deck config when tapping add button', () => { render(props) + fireEvent.click(screen.getAllByText('Select options')[1]) fireEvent.click(screen.getAllByText('Add')[0]) expect(mockSetCurrentDeckConfig).toHaveBeenCalled() }) @@ -74,7 +80,7 @@ describe('Touchscreen AddFixtureModal', () => { render(props) screen.getByText('Add to slot D3') screen.getByText( - 'Choose a fixture below to add to your deck configuration. It will be referenced during protocol analysis.' + 'Choose an item below to add to your deck configuration. It will be referenced during protocol analysis.' ) expect(screen.queryByText('Staging area slot')).toBeNull() screen.getByText('Trash bin') @@ -105,8 +111,12 @@ describe('Desktop AddFixtureModal', () => { render(props) screen.getByText('Add to slot D3') screen.getByText( - 'Add this fixture to your deck configuration. It will be referenced during protocol analysis.' + 'Add this item to your deck configuration. It will be referenced during protocol analysis.' ) + + screen.getByText('Fixtures') + screen.getByText('Modules') + fireEvent.click(screen.getAllByText('Select options')[0]) screen.getByText('Staging area slot') screen.getByText('Trash bin') screen.getByText('Waste chute') @@ -121,8 +131,11 @@ describe('Desktop AddFixtureModal', () => { render(props) screen.getByText('Add to slot A1') screen.getByText( - 'Add this fixture to your deck configuration. It will be referenced during protocol analysis.' + 'Add this item to your deck configuration. It will be referenced during protocol analysis.' ) + screen.getByText('Fixtures') + screen.getByText('Modules') + fireEvent.click(screen.getAllByText('Select options')[0]) screen.getByText('Trash bin') screen.getByRole('button', { name: 'Add' }) }) @@ -132,23 +145,39 @@ describe('Desktop AddFixtureModal', () => { render(props) screen.getByText('Add to slot B3') screen.getByText( - 'Add this fixture to your deck configuration. It will be referenced during protocol analysis.' + 'Add this item to your deck configuration. It will be referenced during protocol analysis.' ) + screen.getByText('Fixtures') + screen.getByText('Modules') + fireEvent.click(screen.getAllByText('Select options')[0]) screen.getByText('Staging area slot') screen.getByText('Trash bin') expect(screen.getAllByRole('button', { name: 'Add' }).length).toBe(2) }) - it('should call a mock function when clicking add button', () => { + it('should only render module options in column 2', () => { + props = { ...props, cutoutId: 'cutoutB2' } + render(props) + screen.getByText('Add to slot B2') + screen.getByText( + 'Add this item to your deck configuration. It will be referenced during protocol analysis.' + ) + screen.getByText('Magnetic Block GEN1') + expect(screen.getByRole('button', { name: 'Add' })).toBeInTheDocument() + }) + + it('should call update deck config when add button is clicked', () => { props = { ...props, cutoutId: 'cutoutA1' } render(props) - fireEvent.click(screen.getByRole('button', { name: 'Add' })) + fireEvent.click(screen.getAllByText('Select options')[1]) + fireEvent.click(screen.getByText('Add')) expect(mockUpdateDeckConfiguration).toHaveBeenCalled() }) it('should display appropriate Waste Chute options when the generic Waste Chute button is clicked', () => { render(props) - fireEvent.click(screen.getByRole('button', { name: 'Select options' })) + fireEvent.click(screen.getAllByText('Select options')[0]) // click fixtures + fireEvent.click(screen.getByRole('button', { name: 'Select options' })) // click waste chute options expect(screen.getAllByRole('button', { name: 'Add' }).length).toBe( WASTE_CHUTE_FIXTURES.length ) @@ -161,6 +190,7 @@ describe('Desktop AddFixtureModal', () => { it('should allow a user to exit the Waste Chute submenu by clicking "go back"', () => { render(props) + fireEvent.click(screen.getAllByText('Select options')[0]) // click fixtures fireEvent.click(screen.getByRole('button', { name: 'Select options' })) fireEvent.click(screen.getByText('Go back')) diff --git a/app/src/organisms/DeviceDetailsDeckConfiguration/__tests__/DeviceDetailsDeckConfiguration.test.tsx b/app/src/organisms/DeviceDetailsDeckConfiguration/__tests__/DeviceDetailsDeckConfiguration.test.tsx index f3b008320af..e6d048bcf52 100644 --- a/app/src/organisms/DeviceDetailsDeckConfiguration/__tests__/DeviceDetailsDeckConfiguration.test.tsx +++ b/app/src/organisms/DeviceDetailsDeckConfiguration/__tests__/DeviceDetailsDeckConfiguration.test.tsx @@ -5,7 +5,7 @@ import { describe, it, beforeEach, vi, afterEach } from 'vitest' import { DeckConfigurator } from '@opentrons/components' import { - useDeckConfigurationQuery, + useModulesQuery, useUpdateDeckConfigurationMutation, } from '@opentrons/react-api-client' @@ -16,6 +16,7 @@ import { DeckFixtureSetupInstructionsModal } from '../DeckFixtureSetupInstructio import { useIsEstopNotDisengaged } from '../../../resources/devices/hooks/useIsEstopNotDisengaged' import { DeviceDetailsDeckConfiguration } from '../' import { useNotifyCurrentMaintenanceRun } from '../../../resources/maintenance_runs' +import { useNotifyDeckConfigurationQuery } from '../../../resources/deck_configuration' import type { MaintenanceRun } from '@opentrons/api-client' import type * as OpentronsComponents from '@opentrons/components' @@ -32,6 +33,7 @@ vi.mock('../DeckFixtureSetupInstructionsModal') vi.mock('../../Devices/hooks') vi.mock('../../../resources/maintenance_runs') vi.mock('../../../resources/devices/hooks/useIsEstopNotDisengaged') +vi.mock('../../../resources/deck_configuration') const ROBOT_NAME = 'otie' const mockUpdateDeckConfiguration = vi.fn() @@ -60,7 +62,10 @@ describe('DeviceDetailsDeckConfiguration', () => { props = { robotName: ROBOT_NAME, } - vi.mocked(useDeckConfigurationQuery).mockReturnValue({ data: [] } as any) + vi.mocked(useModulesQuery).mockReturnValue({ data: { data: [] } } as any) + vi.mocked(useNotifyDeckConfigurationQuery).mockReturnValue({ + data: [], + } as any) vi.mocked(useUpdateDeckConfigurationMutation).mockReturnValue({ updateDeckConfiguration: mockUpdateDeckConfiguration, } as any) @@ -89,7 +94,7 @@ describe('DeviceDetailsDeckConfiguration', () => { screen.getByText('otie deck configuration') screen.getByRole('button', { name: 'Setup Instructions' }) screen.getByText('Location') - screen.getByText('Fixture') + screen.getByText('Deck hardware') screen.getByText('mock DeckConfigurator') }) @@ -127,7 +132,7 @@ describe('DeviceDetailsDeckConfiguration', () => { }) it('should render no deck fixtures, if deck configs are not set', () => { - vi.mocked(useDeckConfigurationQuery).mockReturnValue([] as any) + vi.mocked(useNotifyDeckConfigurationQuery).mockReturnValue([] as any) render(props) screen.getByText('No deck fixtures') }) diff --git a/app/src/organisms/DeviceDetailsDeckConfiguration/index.tsx b/app/src/organisms/DeviceDetailsDeckConfiguration/index.tsx index 9c1d852253a..b6f62c8c08a 100644 --- a/app/src/organisms/DeviceDetailsDeckConfiguration/index.tsx +++ b/app/src/organisms/DeviceDetailsDeckConfiguration/index.tsx @@ -20,7 +20,7 @@ import { TYPOGRAPHY, } from '@opentrons/components' import { - useDeckConfigurationQuery, + useModulesQuery, useUpdateDeckConfigurationMutation, } from '@opentrons/react-api-client' import { @@ -30,6 +30,10 @@ import { SINGLE_SLOT_FIXTURES, SINGLE_LEFT_SLOT_FIXTURE, SINGLE_RIGHT_SLOT_FIXTURE, + SINGLE_CENTER_SLOT_FIXTURE, + SINGLE_LEFT_CUTOUTS, + getDeckDefFromRobotType, + FLEX_ROBOT_TYPE, } from '@opentrons/shared-data' import { useNotifyCurrentMaintenanceRun } from '../../resources/maintenance_runs' @@ -38,8 +42,9 @@ import { DeckFixtureSetupInstructionsModal } from './DeckFixtureSetupInstruction import { AddFixtureModal } from './AddFixtureModal' import { useIsRobotViewable, useRunStatuses } from '../Devices/hooks' import { useIsEstopNotDisengaged } from '../../resources/devices/hooks/useIsEstopNotDisengaged' +import { useNotifyDeckConfigurationQuery } from '../../resources/deck_configuration' -import type { CutoutId } from '@opentrons/shared-data' +import type { CutoutFixtureId, CutoutId } from '@opentrons/shared-data' const DECK_CONFIG_REFETCH_INTERVAL = 5000 const RUN_REFETCH_INTERVAL = 5000 @@ -48,10 +53,14 @@ interface DeviceDetailsDeckConfigurationProps { robotName: string } +function getDisplayLocationForCutoutIds(cutouts: CutoutId[]): string { + return cutouts.map(cutoutId => getCutoutDisplayName(cutoutId)).join(' + ') +} + export function DeviceDetailsDeckConfiguration({ robotName, }: DeviceDetailsDeckConfigurationProps): JSX.Element | null { - const { t } = useTranslation('device_details') + const { t, i18n } = useTranslation('device_details') const [ showSetupInstructionsModal, setShowSetupInstructionsModal, @@ -63,9 +72,12 @@ export function DeviceDetailsDeckConfiguration({ null ) + const { data: modulesData } = useModulesQuery() const deckConfig = - useDeckConfigurationQuery({ refetchInterval: DECK_CONFIG_REFETCH_INTERVAL }) - .data ?? [] + useNotifyDeckConfigurationQuery({ + refetchInterval: DECK_CONFIG_REFETCH_INTERVAL, + }).data ?? [] + const deckDef = getDeckDefFromRobotType(FLEX_ROBOT_TYPE) const { updateDeckConfiguration } = useUpdateDeckConfigurationMutation() const { isRunRunning } = useRunStatuses() const { data: maintenanceRunData } = useNotifyCurrentMaintenanceRun({ @@ -80,26 +92,109 @@ export function DeviceDetailsDeckConfiguration({ setShowAddFixtureModal(true) } - const handleClickRemove = (cutoutId: CutoutId): void => { - const isRightCutout = SINGLE_RIGHT_CUTOUTS.includes(cutoutId) - const singleSlotFixture = isRightCutout - ? SINGLE_RIGHT_SLOT_FIXTURE - : SINGLE_LEFT_SLOT_FIXTURE + const handleClickRemove = ( + cutoutId: CutoutId, + cutoutFixtureId: CutoutFixtureId + ): void => { + let replacementFixtureId: CutoutFixtureId = SINGLE_CENTER_SLOT_FIXTURE + if (SINGLE_RIGHT_CUTOUTS.includes(cutoutId)) { + replacementFixtureId = SINGLE_RIGHT_SLOT_FIXTURE + } else if (SINGLE_LEFT_CUTOUTS.includes(cutoutId)) { + replacementFixtureId = SINGLE_LEFT_SLOT_FIXTURE + } - const newDeckConfig = deckConfig.map(fixture => - fixture.cutoutId === cutoutId - ? { ...fixture, cutoutFixtureId: singleSlotFixture } - : fixture - ) + const fixtureGroup = + deckDef.cutoutFixtures.find(cf => cf.id === cutoutFixtureId) + ?.fixtureGroup ?? {} + let newDeckConfig = deckConfig + if (cutoutId in fixtureGroup) { + const groupMap = + fixtureGroup[cutoutId]?.find(group => + Object.entries(group).every(([cId, cfId]) => + deckConfig.find( + config => + config.cutoutId === cId && config.cutoutFixtureId === cfId + ) + ) + ) ?? {} + newDeckConfig = deckConfig.map(cutoutConfig => + cutoutConfig.cutoutId in groupMap + ? { + ...cutoutConfig, + cutoutFixtureId: replacementFixtureId, + opentronsModuleSerialNumber: undefined, + } + : cutoutConfig + ) + } else { + newDeckConfig = deckConfig.map(cutoutConfig => + cutoutConfig.cutoutId === cutoutId + ? { + ...cutoutConfig, + cutoutFixtureId: replacementFixtureId, + opentronsModuleSerialNumber: undefined, + } + : cutoutConfig + ) + } updateDeckConfiguration(newDeckConfig) } // do not show standard slot in fixture display list - const fixtureDisplayList = deckConfig.filter( - fixture => - fixture.cutoutFixtureId != null && - !SINGLE_SLOT_FIXTURES.includes(fixture.cutoutFixtureId) + const { displayList: fixtureDisplayList } = deckConfig.reduce<{ + displayList: Array<{ displayLocation: string; displayName: string }> + groupedCutoutIds: CutoutId[] + }>( + (acc, { cutoutId, cutoutFixtureId, opentronsModuleSerialNumber }) => { + if ( + cutoutFixtureId == null || + SINGLE_SLOT_FIXTURES.includes(cutoutFixtureId) + ) { + return acc + } + const displayName = getFixtureDisplayName( + cutoutFixtureId, + modulesData?.data.find( + m => m.serialNumber === opentronsModuleSerialNumber + )?.usbPort.port + ) + const fixtureGroup = + deckDef.cutoutFixtures.find(cf => cf.id === cutoutFixtureId) + ?.fixtureGroup ?? {} + if (cutoutId in fixtureGroup) { + const groupMap = + fixtureGroup[cutoutId]?.find(group => + Object.entries(group).every(([cId, cfId]) => + deckConfig.find( + config => + config.cutoutId === cId && config.cutoutFixtureId === cfId + ) + ) + ) ?? {} + const groupedCutoutIds = Object.keys(groupMap) as CutoutId[] + const displayLocation = getDisplayLocationForCutoutIds(groupedCutoutIds) + if (acc.groupedCutoutIds.includes(cutoutId)) { + return acc // only list grouped fixtures once + } else { + return { + displayList: [...acc.displayList, { displayLocation, displayName }], + groupedCutoutIds: [...acc.groupedCutoutIds, ...groupedCutoutIds], + } + } + } + return { + ...acc, + displayList: [ + ...acc.displayList, + { + displayLocation: getDisplayLocationForCutoutIds([cutoutId]), + displayName, + }, + ], + } + }, + { displayList: [], groupedCutoutIds: [] } ) return ( @@ -132,11 +227,7 @@ export function DeviceDetailsDeckConfiguration({ width="100%" borderBottom={BORDERS.lineBorder} > - + {`${robotName} ${t('deck_configuration')}`} cutoutId) } deckConfig={deckConfig} handleClickAdd={handleClickAdd} @@ -197,30 +288,28 @@ export function DeviceDetailsDeckConfiguration({ width="32rem" > - {t('location')} - {t('fixture')} + {t('location')} + + {i18n.format(t('deck_hardware'), 'capitalize')} + {fixtureDisplayList.length > 0 ? ( - fixtureDisplayList.map(fixture => ( + fixtureDisplayList.map(({ displayLocation, displayName }) => ( - - {getCutoutDisplayName(fixture.cutoutId)} - - - {getFixtureDisplayName(fixture.cutoutFixtureId)} - + {displayLocation} + {displayName} )) ) : ( @@ -248,11 +337,7 @@ export function DeviceDetailsDeckConfiguration({ paddingBottom={SPACING.spacing24} width="100%" > - + {t('offline_deck_configuration')} diff --git a/app/src/organisms/Devices/ConnectionTroubleshootingModal.tsx b/app/src/organisms/Devices/ConnectionTroubleshootingModal.tsx index 560eedb235b..03cbde6898a 100644 --- a/app/src/organisms/Devices/ConnectionTroubleshootingModal.tsx +++ b/app/src/organisms/Devices/ConnectionTroubleshootingModal.tsx @@ -48,7 +48,7 @@ export function ConnectionTroubleshootingModal(props: Props): JSX.Element { steps={[t('restart_the_robot'), t('restart_the_app')]} /> - {t('contact_support_for_connection_help', { + {t('branded:contact_support_for_connection_help', { support_email: SUPPORT_EMAIL, })} diff --git a/app/src/organisms/Devices/HistoricalProtocolRunOverflowMenu.tsx b/app/src/organisms/Devices/HistoricalProtocolRunOverflowMenu.tsx index bf06e0db263..ad7badae3cd 100644 --- a/app/src/organisms/Devices/HistoricalProtocolRunOverflowMenu.tsx +++ b/app/src/organisms/Devices/HistoricalProtocolRunOverflowMenu.tsx @@ -29,10 +29,10 @@ import { useRunControls } from '../../organisms/RunTimeControl/hooks' import { useTrackEvent, ANALYTICS_PROTOCOL_PROCEED_TO_RUN, - ANALYTICS_PROTOCOL_RUN_AGAIN, + ANALYTICS_PROTOCOL_RUN_ACTION, } from '../../redux/analytics' import { getRobotUpdateDisplayInfo } from '../../redux/robot-update' -import { useDownloadRunLog, useTrackProtocolRunEvent } from './hooks' +import { useDownloadRunLog, useTrackProtocolRunEvent, useRobot } from './hooks' import { useIsEstopNotDisengaged } from '../../resources/devices/hooks/useIsEstopNotDisengaged' import type { Run } from '@opentrons/api-client' @@ -132,6 +132,9 @@ function MenuDropdown(props: MenuDropdownProps): JSX.Element { const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId, robotName) const { reset } = useRunControls(runId, onResetSuccess) const { deleteRun } = useDeleteRunMutation() + const robot = useRobot(robotName) + const robotSerialNumber = + robot?.health?.robot_serial ?? robot?.serverHealth?.serialNumber ?? null const handleResetClick: React.MouseEventHandler = ( e @@ -142,9 +145,12 @@ function MenuDropdown(props: MenuDropdownProps): JSX.Element { reset() trackEvent({ name: ANALYTICS_PROTOCOL_PROCEED_TO_RUN, - properties: { sourceLocation: 'HistoricalProtocolRun' }, + properties: { + sourceLocation: 'HistoricalProtocolRun', + robotSerialNumber, + }, }) - trackProtocolRunEvent({ name: ANALYTICS_PROTOCOL_RUN_AGAIN }) + trackProtocolRunEvent({ name: ANALYTICS_PROTOCOL_RUN_ACTION.AGAIN }) } const handleDeleteClick: React.MouseEventHandler = e => { diff --git a/app/src/organisms/Devices/InstrumentsAndModules.tsx b/app/src/organisms/Devices/InstrumentsAndModules.tsx index 07b78af63cb..bb4bca6547a 100644 --- a/app/src/organisms/Devices/InstrumentsAndModules.tsx +++ b/app/src/organisms/Devices/InstrumentsAndModules.tsx @@ -25,14 +25,12 @@ import { PipetteRecalibrationWarning } from './PipetteCard/PipetteRecalibrationW import { useCurrentRunId } from '../ProtocolUpload/hooks' import { ModuleCard } from '../ModuleCard' import { useIsFlex, useIsRobotViewable, useRunStatuses } from './hooks' -import { - getIs96ChannelPipetteAttached, - getShowPipetteCalibrationWarning, -} from './utils' +import { getShowPipetteCalibrationWarning } from './utils' import { PipetteCard } from './PipetteCard' import { FlexPipetteCard } from './PipetteCard/FlexPipetteCard' import { GripperCard } from '../GripperCard' import { useIsEstopNotDisengaged } from '../../resources/devices/hooks/useIsEstopNotDisengaged' +import { useModuleApiRequests } from '../ModuleCard/utils' import type { BadGripper, @@ -62,6 +60,7 @@ export function InstrumentsAndModules({ const currentRunId = useCurrentRunId() const { isRunTerminal, isRunRunning } = useRunStatuses() const isEstopNotDisengaged = useIsEstopNotDisengaged(robotName) + const [getLatestRequestId, handleModuleApiRequests] = useModuleApiRequests() const { data: attachedInstruments } = useInstrumentsQuery({ refetchInterval: EQUIPMENT_POLL_MS, @@ -97,9 +96,8 @@ export function InstrumentsAndModules({ !i.ok && i.subsystem === 'pipette_right' ) ?? null - const is96ChannelAttached = getIs96ChannelPipetteAttached( - attachedPipettes?.left ?? null - ) + const is96ChannelAttached = attachedLeftPipette?.data.channels === 96 + const attachPipetteRequired = attachedLeftPipette == null && attachedRightPipette == null const calibratePipetteRequired = @@ -218,6 +216,8 @@ export function InstrumentsAndModules({ attachPipetteRequired={attachPipetteRequired} calibratePipetteRequired={calibratePipetteRequired} updatePipetteFWRequired={updatePipetteFWRequired} + latestRequestId={getLatestRequestId(module.serialNumber)} + handleModuleApiRequests={handleModuleApiRequests} /> ))} @@ -267,6 +267,8 @@ export function InstrumentsAndModules({ attachPipetteRequired={attachPipetteRequired} calibratePipetteRequired={calibratePipetteRequired} updatePipetteFWRequired={updatePipetteFWRequired} + latestRequestId={getLatestRequestId(module.serialNumber)} + handleModuleApiRequests={handleModuleApiRequests} /> ))} diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader.tsx index 8d65ef71417..704c234401e 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader.tsx @@ -15,6 +15,7 @@ import { RUN_STATUS_SUCCEEDED, RUN_STATUS_BLOCKED_BY_OPEN_DOOR, RUN_STATUS_AWAITING_RECOVERY, + RUN_STATUSES_TERMINAL, } from '@opentrons/api-client' import { useModulesQuery, @@ -61,11 +62,7 @@ import { Banner } from '../../../atoms/Banner' import { useTrackEvent, ANALYTICS_PROTOCOL_PROCEED_TO_RUN, - ANALYTICS_PROTOCOL_RUN_AGAIN, - ANALYTICS_PROTOCOL_RUN_FINISH, - ANALYTICS_PROTOCOL_RUN_PAUSE, - ANALYTICS_PROTOCOL_RUN_START, - ANALYTICS_PROTOCOL_RUN_RESUME, + ANALYTICS_PROTOCOL_RUN_ACTION, } from '../../../redux/analytics' import { getIsHeaterShakerAttached } from '../../../redux/config' import { Tooltip } from '../../../atoms/Tooltip' @@ -128,11 +125,6 @@ const CANCELLABLE_STATUSES = [ RUN_STATUS_IDLE, RUN_STATUS_AWAITING_RECOVERY, ] -const RUN_OVER_STATUSES: RunStatus[] = [ - RUN_STATUS_FAILED, - RUN_STATUS_STOPPED, - RUN_STATUS_SUCCEEDED, -] interface ProtocolRunHeaderProps { protocolRunHeaderRef: React.RefObject | null @@ -174,7 +166,6 @@ export function ProtocolRunHeader({ const [pipettesWithTip, setPipettesWithTip] = React.useState< PipettesWithTip[] >([]) - const [closeTerminalBanner, setCloseTerminalBanner] = React.useState(false) const isResetRunLoadingRef = React.useRef(false) const { data: runRecord } = useNotifyRunQuery(runId, { staleTime: Infinity }) const highestPriorityError = @@ -200,7 +191,7 @@ export function ProtocolRunHeader({ const { data: doorStatus } = useDoorQuery({ refetchInterval: EQUIPMENT_POLL_MS, }) - let isDoorOpen = false + let isDoorOpen: boolean if (isFlex) { isDoorOpen = doorStatus?.data.status === 'open' } else if (!isFlex && Boolean(doorSafetySetting?.value)) { @@ -215,7 +206,11 @@ export function ProtocolRunHeader({ if (runStatus === RUN_STATUS_IDLE) { setShowDropTipBanner(true) setPipettesWithTip([]) - } else if (runStatus != null && RUN_OVER_STATUSES.includes(runStatus)) { + } else if ( + runStatus != null && + // @ts-expect-error runStatus expected to possibly not be terminal + RUN_STATUSES_TERMINAL.includes(runStatus) + ) { getPipettesWithTipAttached({ host, runId, @@ -248,10 +243,12 @@ export function ProtocolRunHeader({ } }, [protocolData, isRobotViewable, history]) + // Side effects dependent on the current run state. React.useEffect(() => { + // After a user-initiated stopped run, close the run current run automatically. if (runStatus === RUN_STATUS_STOPPED && isRunCurrent && runId != null) { trackProtocolRunEvent({ - name: ANALYTICS_PROTOCOL_RUN_FINISH, + name: ANALYTICS_PROTOCOL_RUN_ACTION.FINISH, properties: { ...robotAnalyticsData, }, @@ -260,12 +257,6 @@ export function ProtocolRunHeader({ } }, [runStatus, isRunCurrent, runId, closeCurrentRun]) - React.useEffect(() => { - if (runStatus === RUN_STATUS_IDLE) { - setCloseTerminalBanner(false) - } - }, [runStatus]) - const startedAtTimestamp = startedAt != null ? formatTimestamp(startedAt) : EMPTY_TIMESTAMP @@ -306,11 +297,10 @@ export function ProtocolRunHeader({ const handleClearClick = (): void => { trackProtocolRunEvent({ - name: ANALYTICS_PROTOCOL_RUN_FINISH, + name: ANALYTICS_PROTOCOL_RUN_ACTION.FINISH, properties: robotAnalyticsData ?? undefined, }) closeCurrentRun() - setCloseTerminalBanner(true) } return ( @@ -375,7 +365,7 @@ export function ProtocolRunHeader({ CANCELLABLE_STATUSES.includes(runStatus) ? ( {t('shared:close_robot_door')} ) : null} - {mostRecentRunId === runId && !closeTerminalBanner ? ( + {mostRecentRunId === runId ? ( ) : null} {mostRecentRunId === runId && @@ -479,7 +470,9 @@ export function ProtocolRunHeader({ setShowDropTipWizard(false) setPipettesWithTip(prevPipettesWithTip => { const pipettesWithTip = prevPipettesWithTip.slice(1) ?? [] - if (pipettesWithTip.length === 0) closeCurrentRun() + if (pipettesWithTip.length === 0) { + closeCurrentRun() + } return pipettesWithTip }) }} @@ -570,6 +563,7 @@ interface ActionButtonProps { isResetRunLoadingRef: React.MutableRefObject } +// TODO(jh, 04-22-2024): Refactor switch cases into separate factories to increase readability and testability. function ActionButton(props: ActionButtonProps): JSX.Element { const { runId, @@ -613,9 +607,7 @@ function ActionButton(props: ActionButtonProps): JSX.Element { robotName, runId ) - const [showIsShakingModal, setShowIsShakingModal] = React.useState( - false - ) + const [showIsShakingModal, setShowIsShakingModal] = React.useState(false) const isSetupComplete = isCalibrationComplete && isModuleCalibrationComplete && @@ -705,7 +697,7 @@ function ActionButton(props: ActionButtonProps): JSX.Element { buttonText = t('pause_run') handleButtonClick = (): void => { pause() - trackProtocolRunEvent({ name: ANALYTICS_PROTOCOL_RUN_PAUSE }) + trackProtocolRunEvent({ name: ANALYTICS_PROTOCOL_RUN_ACTION.PAUSE }) } } else if (runStatus === RUN_STATUS_STOP_REQUESTED) { buttonIconName = 'ot-spinner' @@ -729,8 +721,8 @@ function ActionButton(props: ActionButtonProps): JSX.Element { trackProtocolRunEvent({ name: runStatus === RUN_STATUS_IDLE - ? ANALYTICS_PROTOCOL_RUN_START - : ANALYTICS_PROTOCOL_RUN_RESUME, + ? ANALYTICS_PROTOCOL_RUN_ACTION.START + : ANALYTICS_PROTOCOL_RUN_ACTION.RESUME, properties: runStatus === RUN_STATUS_IDLE && robotAnalyticsData != null ? robotAnalyticsData @@ -748,7 +740,7 @@ function ActionButton(props: ActionButtonProps): JSX.Element { properties: { sourceLocation: 'RunRecordDetail', robotSerialNumber }, }) trackProtocolRunEvent({ - name: ANALYTICS_PROTOCOL_RUN_AGAIN, + name: ANALYTICS_PROTOCOL_RUN_ACTION.AGAIN, }) } } @@ -804,12 +796,14 @@ function ActionButton(props: ActionButtonProps): JSX.Element { ) } +// TODO(jh 04-24-2024): Split TerminalRunBanner into a RunSuccessBanner and RunFailedBanner. interface TerminalRunProps { runStatus: RunStatus | null handleClearClick: () => void isClosingCurrentRun: boolean setShowRunFailedModal: (showRunFailedModal: boolean) => void isResetRunLoading: boolean + isRunCurrent: boolean highestPriorityError?: RunError | null } function TerminalRunBanner(props: TerminalRunProps): JSX.Element | null { @@ -820,51 +814,64 @@ function TerminalRunBanner(props: TerminalRunProps): JSX.Element | null { setShowRunFailedModal, highestPriorityError, isResetRunLoading, + isRunCurrent, } = props const { t } = useTranslation('run_details') - const handleClick = (): void => { + const handleRunSuccessClick = (): void => { + handleClearClick() + } + + const handleFailedRunClick = (): void => { handleClearClick() setShowRunFailedModal(true) } - if ( - isResetRunLoading === false && - (runStatus === RUN_STATUS_FAILED || runStatus === RUN_STATUS_SUCCEEDED) - ) { + const buildSuccessBanner = (): JSX.Element => { return ( - <> - {runStatus === RUN_STATUS_SUCCEEDED ? ( - - - {t('run_completed')} - - - ) : ( - - - - {t('error_info', { - errorType: highestPriorityError?.errorType, - errorCode: highestPriorityError?.errorCode, - })} - + + + {t('run_completed')} + + + ) + } - - {t('view_error')} - - - - )} - + const buildErrorBanner = (): JSX.Element => { + return ( + + + + {t('error_info', { + errorType: highestPriorityError?.errorType, + errorCode: highestPriorityError?.errorCode, + })} + + + + {t('view_error')} + + + ) } - return null + + if ( + runStatus === RUN_STATUS_SUCCEEDED && + isRunCurrent && + !isResetRunLoading + ) { + return buildSuccessBanner() + } else if (runStatus === RUN_STATUS_FAILED && !isResetRunLoading) { + return buildErrorBanner() + } else { + return null + } } diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunModuleControls.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunModuleControls.tsx index fa9aad2e7d1..4930efee2d3 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunModuleControls.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunModuleControls.tsx @@ -10,6 +10,8 @@ import { } from '@opentrons/components' import { ModuleCard } from '../../ModuleCard' import { useModuleRenderInfoForProtocolById } from '../hooks' +import { useModuleApiRequests } from '../../ModuleCard/utils' + import type { BadPipette, PipetteData } from '@opentrons/api-client' interface PipetteStatus { @@ -77,6 +79,7 @@ export const ProtocolRunModuleControls = ({ calibratePipetteRequired, updatePipetteFWRequired, } = usePipetteIsReady() + const [getLatestRequestId, handleModuleApiRequests] = useModuleApiRequests() const moduleRenderInfoForProtocolById = useModuleRenderInfoForProtocolById( runId, @@ -120,6 +123,10 @@ export const ProtocolRunModuleControls = ({ attachPipetteRequired={attachPipetteRequired} calibratePipetteRequired={calibratePipetteRequired} updatePipetteFWRequired={updatePipetteFWRequired} + latestRequestId={getLatestRequestId( + module.attachedModuleMatch.serialNumber + )} + handleModuleApiRequests={handleModuleApiRequests} /> ) : null )} @@ -141,6 +148,10 @@ export const ProtocolRunModuleControls = ({ attachPipetteRequired={attachPipetteRequired} calibratePipetteRequired={calibratePipetteRequired} updatePipetteFWRequired={updatePipetteFWRequired} + latestRequestId={getLatestRequestId( + module.attachedModuleMatch.serialNumber + )} + handleModuleApiRequests={handleModuleApiRequests} /> ) : null )} diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunRunTimeParameters.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunRunTimeParameters.tsx index ea7ec478415..8298084e5a0 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunRunTimeParameters.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunRunTimeParameters.tsx @@ -1,6 +1,11 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' import styled, { css } from 'styled-components' +import { + RUN_ACTION_TYPE_PLAY, + RUN_STATUS_STOPPED, + RUN_STATUSES_TERMINAL, +} from '@opentrons/api-client' import { formatRunTimeParameterValue } from '@opentrons/shared-data' import { ALIGN_CENTER, @@ -23,8 +28,11 @@ import { Banner } from '../../../atoms/Banner' import { Divider } from '../../../atoms/structure' import { Tooltip } from '../../../atoms/Tooltip' import { useMostRecentCompletedAnalysis } from '../../LabwarePositionCheck/useMostRecentCompletedAnalysis' +import { useRunStatus } from '../../RunTimeControl/hooks' +import { useNotifyRunQuery } from '../../../resources/runs' import type { RunTimeParameter } from '@opentrons/shared-data' +import type { RunStatus } from '@opentrons/api-client' interface ProtocolRunRuntimeParametersProps { runId: string @@ -34,18 +42,36 @@ export function ProtocolRunRuntimeParameters({ }: ProtocolRunRuntimeParametersProps): JSX.Element { const { t } = useTranslation('protocol_setup') const mostRecentAnalysis = useMostRecentCompletedAnalysis(runId) - const runTimeParameters = mostRecentAnalysis?.runTimeParameters ?? [] - const hasParameter = runTimeParameters.length > 0 - - const hasCustomValues = runTimeParameters.some( + const runStatus = useRunStatus(runId) + const isRunTerminal = + runStatus == null + ? false + : (RUN_STATUSES_TERMINAL as RunStatus[]).includes(runStatus) + // we access runTimeParameters from the run record rather than the most recent analysis + // because the most recent analysis may not reflect the selected run (e.g. cloning a run + // from a historical protocol run from the device details page) + const run = useNotifyRunQuery(runId).data + const runTimeParameters = + (isRunTerminal + ? run?.data?.runTimeParameters + : mostRecentAnalysis?.runTimeParameters) ?? [] + const hasRunTimeParameters = runTimeParameters.length > 0 + const hasCustomRunTimeParameterValues = runTimeParameters.some( parameter => parameter.value !== parameter.default ) + const runActions = run?.data.actions + const hasRunStarted = runActions?.some( + action => action.actionType === RUN_ACTION_TYPE_PLAY + ) + const isRunCancelledWithoutStarting = + !hasRunStarted && runStatus === RUN_STATUS_STOPPED + return ( <> - - {t('parameters')} - - {hasParameter ? ( + {hasRunTimeParameters ? ( + + {t('parameters')} + + ) : null} + {hasRunTimeParameters ? ( - {hasCustomValues ? t('custom_values') : t('default_values')} + {hasCustomRunTimeParameterValues + ? t('custom_values') + : t('default_values')} ) : null} - {hasParameter ? ( + {hasRunTimeParameters ? ( ) : null} - {!hasParameter ? ( + {!hasRunTimeParameters ? ( - + ) : ( <> diff --git a/app/src/organisms/Devices/ProtocolRun/RunFailedModal.tsx b/app/src/organisms/Devices/ProtocolRun/RunFailedModal.tsx index dbaeff488b8..e03287f5959 100644 --- a/app/src/organisms/Devices/ProtocolRun/RunFailedModal.tsx +++ b/app/src/organisms/Devices/ProtocolRun/RunFailedModal.tsx @@ -51,7 +51,7 @@ export function RunFailedModal({ setShowRunFailedModal, highestPriorityError, }: RunFailedModalProps): JSX.Element | null { - const { i18n, t } = useTranslation(['run_details', 'shared']) + const { i18n, t } = useTranslation(['run_details', 'shared', 'branded']) const modalProps: LegacyModalProps = { type: 'error', title: t('run_failed_modal_title'), @@ -89,7 +89,7 @@ export function RunFailedModal({ - {t('run_failed_modal_description_desktop')} + {t('branded:run_failed_modal_description_desktop')} { - const { t } = useTranslation(['protocol_setup', 'shared']) + const { t } = useTranslation(['protocol_setup', 'shared', 'branded']) const moduleName = getModuleName(props.type) return createPortal( - {t(`secure_labware_explanation_${snakeCase(moduleName)}`)} + {t(`branded:secure_labware_explanation_${snakeCase(moduleName)}`)} { + const modulesOnDeck = protocolModulesInfo.map(module => { const labwareInAdapterInMod = module.nestedLabwareId != null ? initialLoadedLabwareByAdapter[module.nestedLabwareId] diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/SecureLabwareModal.test.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/SecureLabwareModal.test.tsx index 9372114973f..25c59b4e364 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/SecureLabwareModal.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/SecureLabwareModal.test.tsx @@ -27,7 +27,7 @@ describe('SecureLabwareModal', () => { 'Opentrons recommends ensuring your labware locks to the Magnetic Module by adjusting the black plate bracket on top of the module.' ) screen.getByText( - 'Please note there are two sizes of plate brackets supplied with your module: standard and deep well. These brackets can be removed and swapped by unscrewing the modules thumb screw (the silver knob on the front).' + "There are two sizes of plate brackets supplied with your module: standard and deep well. These brackets can be removed and swapped by unscrewing the module's thumb screw (the silver knob on the front)." ) }) it('should render magnetic module type modal and call onCloseClick when button is pressed', () => { @@ -43,7 +43,7 @@ describe('SecureLabwareModal', () => { render(props) screen.getByText('Securing labware to the Thermocycler') screen.getByText( - 'Opentrons recommends securing your labware to the Thermocycler module by closing its latch. Doing so ensures level and accurate plate placement for optimal results.' + 'Opentrons recommends securing your labware to the Thermocycler Module by closing its latch. Doing so ensures level and accurate plate placement for optimal results.' ) }) diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLabwarePositionCheck/HowLPCWorksModal.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLabwarePositionCheck/HowLPCWorksModal.tsx index 52f5d00c758..4e519d8af72 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLabwarePositionCheck/HowLPCWorksModal.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLabwarePositionCheck/HowLPCWorksModal.tsx @@ -22,7 +22,7 @@ interface HowLPCWorksModalProps { } export const HowLPCWorksModal = (props: HowLPCWorksModalProps): JSX.Element => { - const { t } = useTranslation(['protocol_setup', 'shared']) + const { t } = useTranslation(['protocol_setup', 'shared', 'branded']) return createPortal( { /> - {t('why_use_lpc')} + {t('branded:why_use_lpc')} - {Object.values(volumeByWell).reduce((prev, curr) => prev + curr, 0)}{' '} - {MICRO_LITERS} {t('total_vol')} + {Object.values(volumeByWell) + .reduce((prev, curr) => prev + curr, 0) + .toFixed(1)}{' '} + {MICRO_LITERS} @@ -240,8 +240,10 @@ export function LiquidDetailCard(props: LiquidDetailCardProps): JSX.Element { fontSize={TYPOGRAPHY.fontSizeH4} lineHeight={TYPOGRAPHY.lineHeight20} > - {Object.values(volumeByWell).reduce((prev, curr) => prev + curr, 0)}{' '} - {MICRO_LITERS} {t('total_vol')} + {Object.values(volumeByWell) + .reduce((prev, curr) => prev + curr, 0) + .toFixed(1)}{' '} + {MICRO_LITERS} @@ -272,7 +274,7 @@ export function LiquidDetailCard(props: LiquidDetailCardProps): JSX.Element { {well.wellName} - {well.volume} {MICRO_LITERS} + {well.volume.toFixed(1)} {MICRO_LITERS} ) diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLiquids/SetupLiquidsList.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLiquids/SetupLiquidsList.tsx index eafd8880b55..4cba71ef386 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLiquids/SetupLiquidsList.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLiquids/SetupLiquidsList.tsx @@ -269,7 +269,7 @@ export function LiquidsListItem(props: LiquidsListItemProps): JSX.Element { liquidId, labware.labwareId, labwareByLiquidId - )}{' '} + ).toFixed(1)}{' '} {MICRO_LITERS} @@ -337,7 +337,7 @@ export const LiquidsListItemDetails = ( marginLeft={SIZE_AUTO} > - {getTotalVolumePerLiquidId(liquidId, labwareByLiquidId)}{' '} + {getTotalVolumePerLiquidId(liquidId, labwareByLiquidId).toFixed(1)}{' '} {MICRO_LITERS} diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLiquids/SetupLiquidsMap.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLiquids/SetupLiquidsMap.tsx index 0519b557065..352bcf021e8 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLiquids/SetupLiquidsMap.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLiquids/SetupLiquidsMap.tsx @@ -21,13 +21,11 @@ import { THERMOCYCLER_MODULE_V1, } from '@opentrons/shared-data' -import { useAttachedModules } from '../../hooks' import { LabwareInfoOverlay } from '../LabwareInfoOverlay' import { LiquidsLabwareDetailsModal } from './LiquidsLabwareDetailsModal' import { getWellFillFromLabwareId } from './utils' import { getLabwareRenderInfo } from '../utils/getLabwareRenderInfo' import { getStandardDeckViewLayerBlockList } from '../utils/getStandardDeckViewLayerBlockList' -import { getAttachedProtocolModuleMatches } from '../../../ProtocolSetupModulesAndDeck/utils' import { getProtocolModulesInfo } from '../utils/getProtocolModulesInfo' import type { @@ -35,8 +33,6 @@ import type { ProtocolAnalysisOutput, } from '@opentrons/shared-data' -const ATTACHED_MODULE_POLL_MS = 5000 - interface SetupLiquidsMapProps { runId: string protocolAnalysis: CompletedProtocolAnalysis | ProtocolAnalysisOutput | null @@ -50,10 +46,6 @@ export function SetupLiquidsMap( const [liquidDetailsLabwareId, setLiquidDetailsLabwareId] = React.useState< string | null >(null) - const attachedModules = - useAttachedModules({ - refetchInterval: ATTACHED_MODULE_POLL_MS, - }) ?? [] if (protocolAnalysis == null) return null @@ -75,12 +67,7 @@ export function SetupLiquidsMap( const protocolModulesInfo = getProtocolModulesInfo(protocolAnalysis, deckDef) - const attachedProtocolModuleMatches = getAttachedProtocolModuleMatches( - attachedModules, - protocolModulesInfo - ) - - const modulesOnDeck = attachedProtocolModuleMatches.map(module => { + const modulesOnDeck = protocolModulesInfo.map(module => { const labwareInAdapterInMod = module.nestedLabwareId != null ? initialLoadedLabwareByAdapter[module.nestedLabwareId] diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLiquids/__tests__/LiquidDetailCard.test.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLiquids/__tests__/LiquidDetailCard.test.tsx index c85a827bfcb..648d80f8806 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLiquids/__tests__/LiquidDetailCard.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLiquids/__tests__/LiquidDetailCard.test.tsx @@ -53,7 +53,7 @@ describe('LiquidDetailCard', () => { render(props) screen.getByText('Mock Liquid') screen.getByText('Mock Description') - screen.getAllByText(nestedTextMatcher('100 µL')) + screen.getAllByText(nestedTextMatcher('100.0 µL')) }) it('renders clickable box, clicking on it calls track event', () => { @@ -72,7 +72,7 @@ describe('LiquidDetailCard', () => { }) screen.getByText('A1') screen.getByText('B1') - screen.getAllByText(nestedTextMatcher('50 µL')) + screen.getAllByText(nestedTextMatcher('50.0 µL')) }) it('renders well range for volume info if selected', () => { render({ @@ -81,15 +81,14 @@ describe('LiquidDetailCard', () => { volumeByWell: { A1: 50, B1: 50, C1: 50, D1: 50 }, }) screen.getByText('A1: D1') - screen.getByText(nestedTextMatcher('50 µL')) + screen.getByText(nestedTextMatcher('50.0 µL')) }) it('renders liquid name, description, total volume for odd, and clicking item selects the box', () => { vi.mocked(getIsOnDevice).mockReturnValue(true) render(props) screen.getByText('Mock Liquid') screen.getByText('Mock Description') - screen.getAllByText(nestedTextMatcher('100 µL')) - screen.getAllByText(nestedTextMatcher('total volume')) + screen.getAllByText(nestedTextMatcher('100.0 µL')) expect(screen.getByLabelText('liquidBox_odd')).toHaveStyle( `border: ${SPACING.spacing4} solid ${COLORS.grey30}` ) diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLiquids/__tests__/SetupLiquidsList.test.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLiquids/__tests__/SetupLiquidsList.test.tsx index 4dbfd57cf78..4d50b071908 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLiquids/__tests__/SetupLiquidsList.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLiquids/__tests__/SetupLiquidsList.test.tsx @@ -100,7 +100,7 @@ describe('SetupLiquidsList', () => { it('renders the total volume of the liquid, sample display name, and description', () => { render(props) - screen.getAllByText(nestedTextMatcher('400 µL')) + screen.getAllByText(nestedTextMatcher('400.0 µL')) screen.getByText('mock liquid 1') screen.getByText('mock sample') screen.getByText('mock liquid 2') @@ -118,7 +118,7 @@ describe('SetupLiquidsList', () => { screen.getByText('Location') screen.getByText('Labware name') screen.getByText('Volume') - screen.getAllByText(nestedTextMatcher('200 µL')) + screen.getAllByText(nestedTextMatcher('200.0 µL')) screen.getByText('4') screen.getByText('mock labware name') }) diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLiquids/__tests__/SetupLiquidsMap.test.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLiquids/__tests__/SetupLiquidsMap.test.tsx index 81e5a005143..fa9e45852b5 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLiquids/__tests__/SetupLiquidsMap.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLiquids/__tests__/SetupLiquidsMap.test.tsx @@ -212,7 +212,8 @@ describe('SetupLiquidsMap', () => { when(vi.mocked(getAttachedProtocolModuleMatches)) .calledWith( mockFetchModulesSuccessActionPayloadModules, - mockProtocolModuleInfo + mockProtocolModuleInfo, + [] ) .thenReturn([ { @@ -299,7 +300,8 @@ describe('SetupLiquidsMap', () => { when(vi.mocked(getAttachedProtocolModuleMatches)) .calledWith( mockFetchModulesSuccessActionPayloadModules, - mockProtocolModuleInfo + mockProtocolModuleInfo, + [] ) .thenReturn([ { diff --git a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/ChooseModuleToConfigureModal.tsx b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/ChooseModuleToConfigureModal.tsx new file mode 100644 index 00000000000..a2c967ac2a8 --- /dev/null +++ b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/ChooseModuleToConfigureModal.tsx @@ -0,0 +1,275 @@ +import * as React from 'react' +import { createPortal } from 'react-dom' +import { useTranslation } from 'react-i18next' +import { useHistory } from 'react-router-dom' +import { useModulesQuery } from '@opentrons/react-api-client' +import { + ALIGN_CENTER, + BORDERS, + COLORS, + DIRECTION_COLUMN, + DIRECTION_ROW, + Flex, + Icon, + SPACING, + SecondaryButton, + StyledText, + TEXT_ALIGN_CENTER, + TYPOGRAPHY, +} from '@opentrons/components' +import { + getFixtureDisplayName, + getCutoutFixturesForModuleModel, + MAGNETIC_BLOCK_V1, + getModuleDisplayName, +} from '@opentrons/shared-data' +import { getTopPortalEl } from '../../../../App/portal' +import { LegacyModal } from '../../../../molecules/LegacyModal' +import { Modal } from '../../../../molecules/Modal' +import { FixtureOption } from '../../../DeviceDetailsDeckConfiguration/AddFixtureModal' +import { useNotifyDeckConfigurationQuery } from '../../../../resources/deck_configuration' +import { SmallButton } from '../../../../atoms/buttons' +import { useCloseCurrentRun } from '../../../ProtocolUpload/hooks' + +import type { ModuleModel, DeckDefinition } from '@opentrons/shared-data' +import type { AttachedModule } from '@opentrons/api-client' + +const EQUIPMENT_POLL_MS = 5000 +interface ModuleFixtureOption { + moduleModel: ModuleModel + usbPort?: number + serialNumber?: string +} +interface ChooseModuleToConfigureModalProps { + handleConfigureModule: (moduleSerialNumber?: string) => void + onCloseClick: () => void + deckDef: DeckDefinition + isOnDevice: boolean + requiredModuleModel: ModuleModel + robotName: string + displaySlotName: string +} + +export const ChooseModuleToConfigureModal = ( + props: ChooseModuleToConfigureModalProps +): JSX.Element => { + const { + handleConfigureModule, + onCloseClick, + deckDef, + requiredModuleModel, + isOnDevice, + robotName, + displaySlotName, + } = props + const { t } = useTranslation(['protocol_setup', 'shared']) + const attachedModules = + useModulesQuery({ refetchInterval: EQUIPMENT_POLL_MS })?.data?.data ?? [] + const deckConfig = useNotifyDeckConfigurationQuery()?.data ?? [] + const [configuredModuleMatches, unconfiguredModuleMatches] = + attachedModules.reduce<[AttachedModule[], AttachedModule[]]>( + (acc, attachedMod) => { + if (attachedMod.moduleModel === requiredModuleModel) { + return deckConfig.some( + ({ opentronsModuleSerialNumber }) => + attachedMod.serialNumber === opentronsModuleSerialNumber + ) + ? [[...acc[0], attachedMod], acc[1]] + : [acc[0], [...acc[1], attachedMod]] + } + return acc + }, + [[], []] + ) ?? [] + + const connectedOptions: ModuleFixtureOption[] = unconfiguredModuleMatches.map( + attachedMod => ({ + moduleModel: attachedMod.moduleModel, + usbPort: attachedMod.usbPort.port, + serialNumber: attachedMod.serialNumber, + }) + ) + const passiveOptions: ModuleFixtureOption[] = + requiredModuleModel === MAGNETIC_BLOCK_V1 + ? [{ moduleModel: MAGNETIC_BLOCK_V1 }] + : [] + const fixtureOptions = [...connectedOptions, ...passiveOptions].map( + ({ moduleModel, serialNumber, usbPort }) => { + const moduleFixtures = getCutoutFixturesForModuleModel( + moduleModel, + deckDef + ) + return ( + { + handleConfigureModule(serialNumber) + }} + optionName={getFixtureDisplayName(moduleFixtures[0].id, usbPort)} + buttonText={t('shared:add')} + isOnDevice={isOnDevice} + /> + ) + } + ) + + const moduleDisplayName = getModuleDisplayName(requiredModuleModel) + + const contents = + fixtureOptions.length > 0 ? ( + + {t('add_this_deck_hardware')} + + {fixtureOptions} + + + ) : ( + + ) + + return createPortal( + isOnDevice ? ( + + + + + {contents} + + + + + ) : ( + + + {t('add_to_slot', { slotName: displaySlotName })} + + + } + onClose={onCloseClick} + width="27.75rem" + > + + + + {contents} + + + + + ), + getTopPortalEl() + ) +} + +interface NoUnconfiguredModulesProps { + moduleDisplayName: string + displaySlotName: string + configuredModuleMatches: AttachedModule[] + isOnDevice: boolean + robotName: string +} +function NoUnconfiguredModules(props: NoUnconfiguredModulesProps): JSX.Element { + const { + moduleDisplayName, + configuredModuleMatches, + displaySlotName, + isOnDevice, + robotName, + } = props + const { t } = useTranslation('protocol_setup') + const history = useHistory() + const { closeCurrentRun } = useCloseCurrentRun() + const handleCancelRun = (): void => { + closeCurrentRun() + } + const handleNavigateToDeviceDetails = (): void => { + history.push(`/devices/${robotName}`) + } + const exitButton = isOnDevice ? ( + + ) : ( + + {t('exit_to_deck_configuration')} + + ) + + const loadingBlock = ( + + + + {t('plug_in_module_to_configure', { module: moduleDisplayName })} + + + ) + return ( + + {configuredModuleMatches.length > 0 ? ( + <> + + {t('there_are_other_configured_modules', { + module: moduleDisplayName, + })} + + {loadingBlock} + {exitButton} + + ) : ( + <> + + {t('there_are_no_unconfigured_modules', { + module: moduleDisplayName, + slot: displaySlotName, + })} + + {loadingBlock} + + )} + + ) +} diff --git a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/LocationConflictModal.tsx b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/LocationConflictModal.tsx index b4a8e634b0d..f8c19df00a2 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/LocationConflictModal.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/LocationConflictModal.tsx @@ -1,10 +1,7 @@ import * as React from 'react' import { createPortal } from 'react-dom' import { Trans, useTranslation } from 'react-i18next' -import { - useDeckConfigurationQuery, - useUpdateDeckConfigurationMutation, -} from '@opentrons/react-api-client' +import { useUpdateDeckConfigurationMutation } from '@opentrons/react-api-client' import { ALIGN_CENTER, BORDERS, @@ -25,27 +22,32 @@ import { getCutoutDisplayName, getFixtureDisplayName, getModuleDisplayName, - SINGLE_RIGHT_CUTOUTS, - SINGLE_LEFT_SLOT_FIXTURE, - SINGLE_RIGHT_SLOT_FIXTURE, THERMOCYCLER_MODULE_V1, THERMOCYCLER_MODULE_V2, + getCutoutFixturesForModuleModel, + getFixtureIdByCutoutIdFromModuleSlotName, } from '@opentrons/shared-data' + import { getTopPortalEl } from '../../../../App/portal' import { LegacyModal } from '../../../../molecules/LegacyModal' import { Modal } from '../../../../molecules/Modal' import { SmallButton } from '../../../../atoms/buttons/SmallButton' +import { useNotifyDeckConfigurationQuery } from '../../../../resources/deck_configuration' import type { CutoutConfig, CutoutId, CutoutFixtureId, ModuleModel, + DeckDefinition, } from '@opentrons/shared-data' +import { ChooseModuleToConfigureModal } from './ChooseModuleToConfigureModal' interface LocationConflictModalProps { onCloseClick: () => void cutoutId: CutoutId + deckDef: DeckDefinition + robotName: string missingLabwareDisplayName?: string | null requiredFixtureId?: CutoutFixtureId requiredModule?: ModuleModel @@ -58,13 +60,17 @@ export const LocationConflictModal = ( const { onCloseClick, cutoutId, + robotName, missingLabwareDisplayName, requiredFixtureId, requiredModule, + deckDef, isOnDevice = false, } = props const { t, i18n } = useTranslation(['protocol_setup', 'shared']) - const deckConfig = useDeckConfigurationQuery().data ?? [] + + const [showModuleSelect, setShowModuleSelect] = React.useState(false) + const deckConfig = useNotifyDeckConfigurationQuery().data ?? [] const { updateDeckConfiguration } = useUpdateDeckConfigurationMutation() const deckConfigurationAtLocationFixtureId = deckConfig.find( (deckFixture: CutoutConfig) => deckFixture.cutoutId === cutoutId @@ -89,39 +95,54 @@ export const LocationConflictModal = ( ? getFixtureDisplayName(deckConfigurationAtA1) : currentFixtureDisplayName + const handleConfigureModule = (moduleSerialNumber?: string): void => { + if (requiredModule != null) { + const slotName = cutoutId.replace('cutout', '') + const moduleFixtures = getCutoutFixturesForModuleModel( + requiredModule, + deckDef + ) + const moduleFixtureIdByCutoutId = getFixtureIdByCutoutIdFromModuleSlotName( + slotName, + moduleFixtures, + deckDef + ) + + const newDeckConfig = deckConfig.map(existingCutoutConfig => { + const replacementCutoutFixtureId = + moduleFixtureIdByCutoutId[existingCutoutConfig.cutoutId] + return existingCutoutConfig.cutoutId in moduleFixtureIdByCutoutId && + replacementCutoutFixtureId != null + ? { + ...existingCutoutConfig, + cutoutFixtureId: replacementCutoutFixtureId, + opentronsModuleSerialNumber: moduleSerialNumber, + } + : existingCutoutConfig + }) + updateDeckConfiguration(newDeckConfig) + } + onCloseClick() + } + const handleUpdateDeck = (): void => { - if (requiredFixtureId != null) { + if (requiredModule != null) { + setShowModuleSelect(true) + } else if (requiredFixtureId != null) { const newRequiredFixtureDeckConfig = deckConfig.map(fixture => fixture.cutoutId === cutoutId - ? { ...fixture, cutoutFixtureId: requiredFixtureId } + ? { + ...fixture, + cutoutFixtureId: requiredFixtureId, + opentronsModuleSerialNumber: undefined, + } : fixture ) - updateDeckConfiguration(newRequiredFixtureDeckConfig) + onCloseClick() } else { - const isRightCutout = SINGLE_RIGHT_CUTOUTS.includes(cutoutId) - const singleSlotFixture = isRightCutout - ? SINGLE_RIGHT_SLOT_FIXTURE - : SINGLE_LEFT_SLOT_FIXTURE - - const newSingleSlotDeckConfig = deckConfig.map(fixture => - fixture.cutoutId === cutoutId - ? { ...fixture, cutoutFixtureId: singleSlotFixture } - : fixture - ) - - // add A1 and B1 single slot config for thermocycler - const newThermocyclerDeckConfig = isThermocycler - ? newSingleSlotDeckConfig.map(fixture => - fixture.cutoutId === 'cutoutA1' || fixture.cutoutId === 'cutoutB1' - ? { ...fixture, cutoutFixtureId: SINGLE_LEFT_SLOT_FIXTURE } - : fixture - ) - : newSingleSlotDeckConfig - - updateDeckConfiguration(newThermocyclerDeckConfig) + onCloseClick() } - onCloseClick() } let protocolSpecifiesDisplayName = '' @@ -133,6 +154,25 @@ export const LocationConflictModal = ( protocolSpecifiesDisplayName = getModuleDisplayName(requiredModule) } + const displaySlotName = isThermocycler + ? 'A1 + B1' + : getCutoutDisplayName(cutoutId) + + if (showModuleSelect && requiredModule != null) { + return createPortal( + , + getTopPortalEl() + ) + } + return createPortal( isOnDevice ? ( - {t('slot_location', { - slotName: isThermocycler - ? 'A1 + B1' - : getCutoutDisplayName(cutoutId), - })} + {t('slot_location', { slotName: displaySlotName })} - {t('slot_location', { - slotName: isThermocycler - ? 'A1 + B1' - : getCutoutDisplayName(cutoutId), - })} + {t('slot_location', { slotName: displaySlotName })} unknown -} - -export const MultipleModulesModal = ( - props: MultipleModulesModalProps -): JSX.Element => { - const { t } = useTranslation(['protocol_setup', 'shared']) - const isOnDevice = useSelector(getIsOnDevice) - return createPortal( - isOnDevice ? ( - - - {t('multiple_of_most_modules')} - 2 temperature modules plugged into the usb ports - - - ) : ( - - - - - - {t('multiple_modules_explanation')} - - - {t('multiple_modules_learn_more')} - - - - {t('example')} - - - {t('multiple_modules_example')} - - 2 temperature modules plugged into the usb ports - - - {t('shared:close')} - - - - ), - getTopPortalEl() - ) -} diff --git a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/NotConfiguredModal.tsx b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/NotConfiguredModal.tsx index 3ef27d24baa..76ceaf202b6 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/NotConfiguredModal.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/NotConfiguredModal.tsx @@ -1,10 +1,7 @@ import * as React from 'react' import { createPortal } from 'react-dom' import { useTranslation } from 'react-i18next' -import { - useDeckConfigurationQuery, - useUpdateDeckConfigurationMutation, -} from '@opentrons/react-api-client' +import { useUpdateDeckConfigurationMutation } from '@opentrons/react-api-client' import { ALIGN_CENTER, BORDERS, @@ -20,6 +17,7 @@ import { getFixtureDisplayName } from '@opentrons/shared-data' import { TertiaryButton } from '../../../../atoms/buttons/TertiaryButton' import { getTopPortalEl } from '../../../../App/portal' import { LegacyModal } from '../../../../molecules/LegacyModal' +import { useNotifyDeckConfigurationQuery } from '../../../../resources/deck_configuration' import type { CutoutFixtureId, CutoutId } from '@opentrons/shared-data' @@ -35,7 +33,7 @@ export const NotConfiguredModal = ( const { onCloseClick, cutoutId, requiredFixtureId } = props const { t, i18n } = useTranslation(['protocol_setup', 'shared']) const { updateDeckConfiguration } = useUpdateDeckConfigurationMutation() - const deckConfig = useDeckConfigurationQuery()?.data ?? [] + const deckConfig = useNotifyDeckConfigurationQuery()?.data ?? [] const handleUpdateDeck = (): void => { const newDeckConfig = deckConfig.map(fixture => @@ -57,7 +55,7 @@ export const NotConfiguredModal = ( width="27.75rem" > - {t('add_fixture_to_deck')} + {t('add_this_deck_hardware')} (false) + + const onCloseClick = (): void => { + setShowMultipleModulesModal(false) + } + return ( + <> + + setShowMultipleModulesModal(true)} + closeButton={ + + {t('learn_more')} + + } + > + + + {t('multiple_modules')} + + {t('view_moam')} + + + + {showMultipleModulesModal + ? createPortal( + + + + + + {t('multiple_modules_explanation')} + + + {t('multiple_modules_learn_more')} + + + + {t('example')} + + + + {t('multiple_modules_example')} + + + 2 temperature modules plugged into the usb ports + + + {t('shared:close')} + + + , + getTopPortalEl() + ) + : null} + + ) +} diff --git a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/SetupFixtureList.tsx b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/SetupFixtureList.tsx index 4e65fd3759d..3e1b2ebdee9 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/SetupFixtureList.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/SetupFixtureList.tsx @@ -2,6 +2,7 @@ import * as React from 'react' import { css } from 'styled-components' import { useTranslation } from 'react-i18next' import { + ALIGN_FLEX_START, BORDERS, Box, Btn, @@ -16,8 +17,11 @@ import { TYPOGRAPHY, } from '@opentrons/components' import { + FLEX_ROBOT_TYPE, + FLEX_USB_MODULE_ADDRESSABLE_AREAS, SINGLE_SLOT_FIXTURES, getCutoutDisplayName, + getDeckDefFromRobotType, getFixtureDisplayName, } from '@opentrons/shared-data' import { StatusLabel } from '../../../../atoms/StatusLabel' @@ -27,73 +31,55 @@ import { NotConfiguredModal } from './NotConfiguredModal' import { getFixtureImage } from './utils' import { DeckFixtureSetupInstructionsModal } from '../../../DeviceDetailsDeckConfiguration/DeckFixtureSetupInstructionsModal' +import type { DeckDefinition } from '@opentrons/shared-data' import type { CutoutConfigAndCompatibility } from '../../../../resources/deck_configuration/hooks' interface SetupFixtureListProps { deckConfigCompatibility: CutoutConfigAndCompatibility[] + robotName: string } +/** + * List items of all "non-module" fixtures e.g. staging slot, waste chute, trash bin... + * @param props + * @returns JSX.Element + */ export const SetupFixtureList = (props: SetupFixtureListProps): JSX.Element => { - const { deckConfigCompatibility } = props - const { t, i18n } = useTranslation('protocol_setup') + const { deckConfigCompatibility, robotName } = props + const deckDef = getDeckDefFromRobotType(FLEX_ROBOT_TYPE) return ( <> - - - {i18n.format(t('fixture_name'), 'capitalize')} - - - {t('location')} - - - {t('status')} - - - - {deckConfigCompatibility.map(cutoutConfigAndCompatibility => { - return ( - - ) - })} - + {deckConfigCompatibility.map(cutoutConfigAndCompatibility => { + // filter out all fixtures that only provide usb module addressable areas + // (i.e. everything but MagBlockV1 and StagingAreaWithMagBlockV1) + // as they're handled in the Modules Table + return cutoutConfigAndCompatibility.requiredAddressableAreas.every( + raa => FLEX_USB_MODULE_ADDRESSABLE_AREAS.includes(raa) + ) ? null : ( + + ) + })} ) } -interface FixtureListItemProps extends CutoutConfigAndCompatibility {} +interface FixtureListItemProps extends CutoutConfigAndCompatibility { + deckDef: DeckDefinition + robotName: string +} export function FixtureListItem({ cutoutId, cutoutFixtureId, compatibleCutoutFixtureIds, missingLabwareDisplayName, + deckDef, + robotName, }: FixtureListItemProps): JSX.Element { const { t } = useTranslation('protocol_setup') @@ -155,8 +141,10 @@ export function FixtureListItem({ setShowLocationConflictModal(false)} cutoutId={cutoutId} + deckDef={deckDef} missingLabwareDisplayName={missingLabwareDisplayName} requiredFixtureId={compatibleCutoutFixtureIds[0]} + robotName={robotName} /> ) : null} {showSetupInstructionsModal ? ( @@ -190,7 +178,10 @@ export function FixtureListItem({ } /> ) : null} - + { const { robotName, runId } = props - const { t } = useTranslation('protocol_setup') const moduleRenderInfoForProtocolById = useModuleRenderInfoForProtocolById( runId ) @@ -85,125 +85,56 @@ export const SetupModulesList = (props: SetupModulesListProps): JSX.Element => { const calibrationStatus = useRunCalibrationStatus(robotName, runId) - const [ - showMultipleModulesModal, - setShowMultipleModulesModal, - ] = React.useState(false) - const moduleModels = map( moduleRenderInfoForProtocolById, ({ moduleDef }) => moduleDef.model ) - - const hasADuplicateModule = new Set(moduleModels).size !== moduleModels.length - + const showOT2MoamHelp = + robotModel === OT2_ROBOT_TYPE && + new Set(moduleModels).size !== moduleModels.length return ( <> - {showMultipleModulesModal ? ( - setShowMultipleModulesModal(false)} - /> - ) : null} - {hasADuplicateModule ? ( - - setShowMultipleModulesModal(true)} - closeButton={ - - {t('learn_more')} - - } - > - - - {t('multiple_modules')} - - {t('view_moam')} - - - - ) : null} + {showOT2MoamHelp ? : null} {remainingAttachedModules.length !== 0 && missingModuleIds.length !== 0 ? ( ) : null} - - - {t('module_name')} - - - {t('location')} - - - {t('status')} - - - - {map( - moduleRenderInfoForProtocolById, - ({ - moduleDef, - attachedModuleMatch, - slotName, - moduleId, - conflictedFixture, - }) => { - return ( - - ) - } - )} - + + {map( + moduleRenderInfoForProtocolById, + ({ + moduleDef, + attachedModuleMatch, + slotName, + moduleId, + conflictedFixture, + }) => { + // filter out the magnetic block here, because it is handled by the SetupFixturesList + if (moduleDef.moduleType === MAGNETIC_BLOCK_TYPE) return null + return ( + + ) + } + )} ) } @@ -218,6 +149,7 @@ interface ModulesListItemProps { calibrationStatus: ProtocolCalibrationStatus deckDef: DeckDefinition conflictedFixture: CutoutConfig | null + robotName: string } export function ModulesListItem({ @@ -230,6 +162,7 @@ export function ModulesListItem({ calibrationStatus, conflictedFixture, deckDef, + robotName, }: ModulesListItemProps): JSX.Element { const { t } = useTranslation(['protocol_setup', 'module_wizard_flows']) const moduleConnectionStatus = @@ -358,13 +291,14 @@ export function ModulesListItem({ onCloseClick={() => setShowLocationConflictModal(false)} cutoutId={cutoutIdForSlotName} requiredModule={moduleModel} + deckDef={deckDef} + robotName={robotName} /> ) : null} {showModuleWizard && attachedModuleMatch != null ? ( setShowModuleWizard(false)} - initialSlotName={slotName} isPrepCommandLoading={isCommandMutationLoading} prepCommandErrorMessage={ prepCommandErrorMessage === '' ? undefined : prepCommandErrorMessage @@ -404,13 +338,26 @@ export function ModulesListItem({ {subText} - - {getModuleType(moduleModel) === 'thermocyclerModuleType' - ? isFlex - ? TC_MODULE_LOCATION_OT3 - : TC_MODULE_LOCATION_OT2 - : slotName} - + + + {getModuleType(moduleModel) === 'thermocyclerModuleType' + ? isFlex + ? TC_MODULE_LOCATION_OT3 + : TC_MODULE_LOCATION_OT2 + : slotName} + + {attachedModuleMatch?.usbPort.port != null ? ( + + {t('usb_port_number', { + port: attachedModuleMatch.usbPort.port, + })} + + ) : null} + ({ @@ -64,7 +70,9 @@ export const SetupModulesMap = ({ ), })) - const deckConfig = getSimplestDeckConfigForProtocol(protocolAnalysis) + const simplestProtocolDeckConfig = getSimplestDeckConfigForProtocol( + protocolAnalysis + ) return ( ({ - cutoutId, - cutoutFixtureId, - }))} + deckConfig={simplestProtocolDeckConfig.map( + ({ cutoutId, cutoutFixtureId }) => ({ + cutoutId, + cutoutFixtureId, + }) + )} deckLayerBlocklist={getStandardDeckViewLayerBlockList(robotType)} robotType={robotType} labwareOnDeck={[]} diff --git a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/LocationConflictModal.test.tsx b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/LocationConflictModal.test.tsx index 82e31c1c7a7..5314acbb283 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/LocationConflictModal.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/LocationConflictModal.test.tsx @@ -1,5 +1,6 @@ import * as React from 'react' import { UseQueryResult } from 'react-query' +import { MemoryRouter } from 'react-router-dom' import { screen, fireEvent } from '@testing-library/react' import '@testing-library/jest-dom/vitest' import { describe, it, beforeEach, vi, afterEach, expect } from 'vitest' @@ -8,17 +9,24 @@ import { SINGLE_RIGHT_SLOT_FIXTURE, STAGING_AREA_RIGHT_SLOT_FIXTURE, TRASH_BIN_ADAPTER_FIXTURE, + ot3StandardDeckV5, } from '@opentrons/shared-data' import { - useDeckConfigurationQuery, + useModulesQuery, useUpdateDeckConfigurationMutation, } from '@opentrons/react-api-client' + import { i18n } from '../../../../../i18n' +import { mockHeaterShaker } from '../../../../../redux/modules/__fixtures__' +import { useCloseCurrentRun } from '../../../../ProtocolUpload/hooks' import { LocationConflictModal } from '../LocationConflictModal' +import { useNotifyDeckConfigurationQuery } from '../../../../../resources/deck_configuration' import type { DeckConfiguration } from '@opentrons/shared-data' vi.mock('@opentrons/react-api-client') +vi.mock('../../../../../resources/deck_configuration') +vi.mock('../../../../ProtocolUpload/hooks') const mockFixture = { cutoutId: 'cutoutB3', @@ -26,9 +34,14 @@ const mockFixture = { } const render = (props: React.ComponentProps) => { - return renderWithProviders(, { - i18nInstance: i18n, - })[0] + return renderWithProviders( + + + , + { + i18nInstance: i18n, + } + )[0] } describe('LocationConflictModal', () => { @@ -39,8 +52,14 @@ describe('LocationConflictModal', () => { onCloseClick: vi.fn(), cutoutId: 'cutoutB3', requiredFixtureId: TRASH_BIN_ADAPTER_FIXTURE, + deckDef: ot3StandardDeckV5 as any, + robotName: 'otie', } - vi.mocked(useDeckConfigurationQuery).mockReturnValue({ + vi.mocked(useCloseCurrentRun).mockReturnValue({ + closeCurrentRun: vi.fn(), + } as any) + vi.mocked(useModulesQuery).mockReturnValue({ data: { data: [] } } as any) + vi.mocked(useNotifyDeckConfigurationQuery).mockReturnValue({ data: [mockFixture], } as UseQueryResult) vi.mocked(useUpdateDeckConfigurationMutation).mockReturnValue({ @@ -64,22 +83,28 @@ describe('LocationConflictModal', () => { expect(mockUpdate).toHaveBeenCalled() }) it('should render the modal information for a module fixture conflict', () => { + vi.mocked(useModulesQuery).mockReturnValue({ + data: { data: [mockHeaterShaker] }, + } as any) props = { onCloseClick: vi.fn(), cutoutId: 'cutoutB3', requiredModule: 'heaterShakerModuleV1', + deckDef: ot3StandardDeckV5 as any, + robotName: 'otie', } render(props) screen.getByText('Protocol specifies') screen.getByText('Currently configured') - screen.getByText('Heater-Shaker Module GEN1') fireEvent.click(screen.getByRole('button', { name: 'Cancel' })) expect(props.onCloseClick).toHaveBeenCalled() fireEvent.click(screen.getByRole('button', { name: 'Update deck' })) + screen.getByText('Heater-Shaker Module GEN1 in USB-1') + fireEvent.click(screen.getByRole('button', { name: 'add' })) expect(mockUpdate).toHaveBeenCalled() }) it('should render the modal information for a single slot fixture conflict', () => { - vi.mocked(useDeckConfigurationQuery).mockReturnValue({ + vi.mocked(useNotifyDeckConfigurationQuery).mockReturnValue({ data: [ { cutoutId: 'cutoutB1', @@ -92,6 +117,8 @@ describe('LocationConflictModal', () => { cutoutId: 'cutoutB1', requiredFixtureId: SINGLE_RIGHT_SLOT_FIXTURE, missingLabwareDisplayName: 'a tiprack', + deckDef: ot3StandardDeckV5 as any, + robotName: 'otie', } render(props) screen.getByText('Deck location conflict') diff --git a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/NotConfiguredModal.test.tsx b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/NotConfiguredModal.test.tsx index f2adbfe736d..e1a29a6a38e 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/NotConfiguredModal.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/NotConfiguredModal.test.tsx @@ -3,17 +3,17 @@ import { fireEvent } from '@testing-library/react' import { describe, it, beforeEach, vi, expect } from 'vitest' import { renderWithProviders } from '../../../../../__testing-utils__' import { TRASH_BIN_ADAPTER_FIXTURE } from '@opentrons/shared-data' -import { - useDeckConfigurationQuery, - useUpdateDeckConfigurationMutation, -} from '@opentrons/react-api-client' +import { useUpdateDeckConfigurationMutation } from '@opentrons/react-api-client' + import { i18n } from '../../../../../i18n' import { NotConfiguredModal } from '../NotConfiguredModal' +import { useNotifyDeckConfigurationQuery } from '../../../../../resources/deck_configuration' import type { UseQueryResult } from 'react-query' import type { DeckConfiguration } from '@opentrons/shared-data' vi.mock('@opentrons/react-api-client') +vi.mock('../../../../../resources/deck_configuration') const render = (props: React.ComponentProps) => { return renderWithProviders(, { @@ -33,7 +33,7 @@ describe('NotConfiguredModal', () => { vi.mocked(useUpdateDeckConfigurationMutation).mockReturnValue({ updateDeckConfiguration: mockUpdate, } as any) - vi.mocked(useDeckConfigurationQuery).mockReturnValue(({ + vi.mocked(useNotifyDeckConfigurationQuery).mockReturnValue(({ data: [], } as unknown) as UseQueryResult) }) @@ -41,7 +41,7 @@ describe('NotConfiguredModal', () => { const { getByText, getByRole } = render(props) getByText('Add Trash bin to deck configuration') getByText( - 'Add this fixture to your deck configuration. It will be referenced during protocol analysis.' + 'Add this deck hardware to your deck configuration. It will be referenced during protocol analysis.' ) getByText('Trash bin') fireEvent.click(getByRole('button', { name: 'Add' })) diff --git a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/MultipleModuleModal.test.tsx b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/OT2MultipleModulesHelp.test.tsx similarity index 60% rename from app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/MultipleModuleModal.test.tsx rename to app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/OT2MultipleModulesHelp.test.tsx index 532ab57c39b..984dc1e57e5 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/MultipleModuleModal.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/OT2MultipleModulesHelp.test.tsx @@ -5,31 +5,30 @@ import { describe, it, beforeEach, vi, expect } from 'vitest' import { renderWithProviders } from '../../../../../__testing-utils__' import { i18n } from '../../../../../i18n' import { getIsOnDevice } from '../../../../../redux/config' -import { MultipleModulesModal } from '../MultipleModulesModal' +import { OT2MultipleModulesHelp } from '../OT2MultipleModulesHelp' vi.mock('../../../../../redux/config') -const render = (props: React.ComponentProps) => { - return renderWithProviders(, { +const render = () => + renderWithProviders(, { i18nInstance: i18n, })[0] -} -describe('MultipleModulesModal', () => { - let props: React.ComponentProps +describe('OT2MultipleModulesHelp', () => { beforeEach(() => { - props = { onCloseClick: vi.fn() } vi.mocked(getIsOnDevice).mockReturnValue(false) }) it('should render the correct header', () => { - render(props) + render() + fireEvent.click(screen.getByText('Learn more')) screen.getByRole('heading', { name: 'Setting up multiple modules of the same type', }) }) it('should render the correct body', () => { - render(props) + render() + fireEvent.click(screen.getByText('Learn more')) screen.getByText( 'To use more than one of the same module in a protocol, you first need to plug in the module that’s called first in your protocol to the lowest numbered USB port on the robot. Continue in the same manner with additional modules.' ) @@ -40,7 +39,8 @@ describe('MultipleModulesModal', () => { screen.getByAltText('2 temperature modules plugged into the usb ports') }) it('should render a link to the learn more page', () => { - render(props) + render() + fireEvent.click(screen.getByText('Learn more')) expect( screen .getByRole('link', { @@ -51,23 +51,13 @@ describe('MultipleModulesModal', () => { 'https://support.opentrons.com/s/article/Using-modules-of-the-same-type-on-the-OT-2' ) }) - it('should call onCloseClick when the close button is pressed', () => { - render(props) - expect(props.onCloseClick).not.toHaveBeenCalled() + it('should call close info modal when the close button is pressed', () => { + render() + fireEvent.click(screen.getByText('Learn more')) const closeButton = screen.getByRole('button', { name: 'close' }) fireEvent.click(closeButton) - expect(props.onCloseClick).toHaveBeenCalled() - }) - it('should render the correct text and img for on device display', () => { - vi.mocked(getIsOnDevice).mockReturnValue(true) - render(props) - screen.getByText( - 'You can use multiples of most module types within a single Python protocol by connecting and loading the modules in a specific order. The robot will initialize the matching module attached to the lowest numbered port first, regardless of what deck slot it occupies.' - ) - const img = screen.getByRole('img') - expect(img.getAttribute('src')).toBe( - '/app/src/assets/images/on-device-display/multiple_modules_modal.png' - ) - screen.getByAltText('2 temperature modules plugged into the usb ports') + expect( + screen.queryByText('Setting up multiple modules of the same type') + ).toBeNull() }) }) diff --git a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/SetupFixtureList.test.tsx b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/SetupFixtureList.test.tsx index 69813bdbd8f..3724d3fc41c 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/SetupFixtureList.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/SetupFixtureList.test.tsx @@ -3,7 +3,10 @@ import { fireEvent, screen } from '@testing-library/react' import { describe, it, beforeEach, vi } from 'vitest' import { renderWithProviders } from '../../../../../__testing-utils__' import { + MAGNETIC_BLOCK_D3_ADDRESSABLE_AREA, + MAGNETIC_BLOCK_V1_FIXTURE, SINGLE_RIGHT_SLOT_FIXTURE, + STAGING_AREA_SLOT_WITH_MAGNETIC_BLOCK_V1_FIXTURE, STAGING_AREA_SLOT_WITH_WASTE_CHUTE_RIGHT_ADAPTER_NO_COVER_FIXTURE, TRASH_BIN_ADAPTER_FIXTURE, } from '@opentrons/shared-data' @@ -69,6 +72,7 @@ describe('SetupFixtureList', () => { beforeEach(() => { props = { deckConfigCompatibility: mockDeckConfigCompatibility, + robotName: 'otie', } vi.mocked(LocationConflictModal).mockReturnValue(
mock location conflict modal
@@ -81,11 +85,8 @@ describe('SetupFixtureList', () => { ) }) - it('should render the headers and a fixture with configured status', () => { + it('should a fixture with configured status', () => { render(props) - screen.getByText('Fixture') - screen.getByText('Location') - screen.getByText('Status') screen.getByText('Waste chute with staging area slot') screen.getByRole('button', { name: 'View setup instructions' }) screen.getByText('D3') @@ -103,6 +104,7 @@ describe('SetupFixtureList', () => { it('should render the headers and a fixture with conflicted status', () => { props = { deckConfigCompatibility: mockConflictDeckConfigCompatibility, + robotName: 'otie', } render(props) screen.getByText('Location conflict') @@ -113,10 +115,32 @@ describe('SetupFixtureList', () => { it('should render the headers and a fixture with not configured status and button', () => { props = { deckConfigCompatibility: mockNotConfiguredDeckConfigCompatibility, + robotName: 'otie', } render(props) screen.getByText('Not configured') fireEvent.click(screen.getByRole('button', { name: 'Resolve' })) screen.getByText('mock not configured modal') }) + it('should render a magnetic block with a conflicted fixture', () => { + props = { + deckConfigCompatibility: [ + { + cutoutId: 'cutoutD3', + cutoutFixtureId: MAGNETIC_BLOCK_V1_FIXTURE, + requiredAddressableAreas: [MAGNETIC_BLOCK_D3_ADDRESSABLE_AREA, 'D4'], + compatibleCutoutFixtureIds: [ + STAGING_AREA_SLOT_WITH_MAGNETIC_BLOCK_V1_FIXTURE, + ], + missingLabwareDisplayName: null, + }, + ], + robotName: 'otie', + } + render(props) + screen.getByText('Location conflict') + screen.getByText('Magnetic Block GEN1 with staging area slot') + fireEvent.click(screen.getByRole('button', { name: 'Resolve' })) + screen.getByText('mock location conflict modal') + }) }) diff --git a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/SetupModulesList.test.tsx b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/SetupModulesList.test.tsx index 05df2fc9cef..ca35acee669 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/SetupModulesList.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/SetupModulesList.test.tsx @@ -3,12 +3,11 @@ import { when } from 'vitest-when' import { fireEvent, screen, waitFor } from '@testing-library/react' import { describe, it, beforeEach, expect, vi } from 'vitest' import { renderWithProviders } from '../../../../../__testing-utils__' -import { STAGING_AREA_RIGHT_SLOT_FIXTURE } from '@opentrons/shared-data' +import { FLEX_ROBOT_TYPE, OT2_ROBOT_TYPE } from '@opentrons/shared-data' import { i18n } from '../../../../../i18n' import { mockMagneticModule as mockMagneticModuleFixture, mockHeaterShaker, - mockMagneticBlock, } from '../../../../../redux/modules/__fixtures__/index' import { mockMagneticModuleGen2, @@ -20,16 +19,17 @@ import { ModuleWizardFlows } from '../../../../ModuleWizardFlows' import { useIsFlex, useModuleRenderInfoForProtocolById, - useRunHasStarted, useUnmatchedModulesForProtocol, useRunCalibrationStatus, + useRobot, } from '../../../hooks' -import { MultipleModulesModal } from '../MultipleModulesModal' +import { OT2MultipleModulesHelp } from '../OT2MultipleModulesHelp' import { UnMatchedModuleWarning } from '../UnMatchedModuleWarning' import { SetupModulesList } from '../SetupModulesList' import { LocationConflictModal } from '../LocationConflictModal' import type { ModuleModel, ModuleType } from '@opentrons/shared-data' +import type { DiscoveredRobot } from '../../../../../redux/discovery/types' vi.mock('@opentrons/react-api-client') vi.mock('../../../hooks') @@ -37,7 +37,7 @@ vi.mock('../LocationConflictModal') vi.mock('../UnMatchedModuleWarning') vi.mock('../../../../ModuleCard/ModuleSetupModal') vi.mock('../../../../ModuleWizardFlows') -vi.mock('../MultipleModulesModal') +vi.mock('../OT2MultipleModulesHelp') vi.mock('../../../../../resources/runs') vi.mock('../../../../../redux/config') @@ -92,6 +92,9 @@ describe('SetupModulesList', () => { robotName: ROBOT_NAME, runId: RUN_ID, } + when(vi.mocked(useRobot)) + .calledWith(ROBOT_NAME) + .thenReturn({ robotModel: FLEX_ROBOT_TYPE } as DiscoveredRobot) mockChainLiveCommands = vi.fn() mockChainLiveCommands.mockResolvedValue(null) vi.mocked(ModuleSetupModal).mockReturnValue(
mockModuleSetupModal
) @@ -118,15 +121,6 @@ describe('SetupModulesList', () => { ) }) - it('should render the list view headers', () => { - when(useRunHasStarted).calledWith(RUN_ID).thenReturn(false) - when(useModuleRenderInfoForProtocolById).calledWith(RUN_ID).thenReturn({}) - render(props) - screen.getByText('Module') - screen.getByText('Location') - screen.getByText('Status') - }) - it('should render a magnetic module that is connected', () => { vi.mocked(useModuleRenderInfoForProtocolById).mockReturnValue({ [mockMagneticModule.moduleId]: { @@ -301,8 +295,13 @@ describe('SetupModulesList', () => { screen.getByText('Connected') }) - it('should render the MoaM component when Moam is attached', () => { - vi.mocked(MultipleModulesModal).mockReturnValue(
mock Moam modal
) + it('should render the MoaM component when Moam is attached and robot is OT2', () => { + when(vi.mocked(useRobot)) + .calledWith(ROBOT_NAME) + .thenReturn({ robotModel: OT2_ROBOT_TYPE } as DiscoveredRobot) + vi.mocked(OT2MultipleModulesHelp).mockReturnValue( +
mock Moam modal
+ ) when(useUnmatchedModulesForProtocol) .calledWith(ROBOT_NAME, RUN_ID) .thenReturn({ @@ -355,8 +354,6 @@ describe('SetupModulesList', () => { }, }) render(props) - const help = screen.getByTestId('Banner_close-button') - fireEvent.click(help) screen.getByText('mock Moam modal') }) it('should render the module unmatching banner', () => { @@ -409,36 +406,4 @@ describe('SetupModulesList', () => { fireEvent.click(moduleSetup) screen.getByText('mockModuleSetupModal') }) - it('should render a magnetic block with a conflicted fixture', () => { - when(useIsFlex).calledWith(ROBOT_NAME).thenReturn(true) - vi.mocked(useModuleRenderInfoForProtocolById).mockReturnValue({ - [mockMagneticBlock.id]: { - moduleId: mockMagneticBlock.id, - x: MOCK_MAGNETIC_MODULE_COORDS[0], - y: MOCK_MAGNETIC_MODULE_COORDS[1], - z: MOCK_MAGNETIC_MODULE_COORDS[2], - moduleDef: { - id: 'magneticBlock_id', - model: mockMagneticBlock.moduleModel, - moduleType: mockMagneticBlock.moduleType, - displayName: mockMagneticBlock.displayName, - }, - nestedLabwareDef: null, - nestedLabwareId: null, - protocolLoadOrder: 0, - slotName: 'B3', - attachedModuleMatch: null, - conflictedFixture: { - cutoutId: 'cutoutB3', - cutoutFixtureId: STAGING_AREA_RIGHT_SLOT_FIXTURE, - }, - }, - } as any) - render(props) - screen.getByText('No USB connection required') - screen.getByText('Location conflict') - screen.getByText('Magnetic Block GEN1') - fireEvent.click(screen.getByRole('button', { name: 'Resolve' })) - screen.getByText('mock location conflict modal') - }) }) diff --git a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/index.tsx b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/index.tsx index 4e9afd58604..0de1a163356 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/index.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/index.tsx @@ -7,6 +7,10 @@ import { SPACING, useHoverTooltip, PrimaryButton, + DIRECTION_ROW, + JUSTIFY_SPACE_BETWEEN, + StyledText, + TYPOGRAPHY, } from '@opentrons/components' import { useToggleGroup } from '../../../../molecules/ToggleGroup/useToggleGroup' @@ -46,7 +50,7 @@ export const SetupModuleAndDeck = ({ hasModules, protocolAnalysis, }: SetupModuleAndDeckProps): JSX.Element => { - const { t } = useTranslation('protocol_setup') + const { t, i18n } = useTranslation('protocol_setup') const [selectedValue, toggleGroup] = useToggleGroup( t('list_view'), t('map_view') @@ -75,14 +79,52 @@ export const SetupModuleAndDeck = ({ {toggleGroup} {selectedValue === t('list_view') ? ( <> - {hasModules ? ( - - ) : null} - {requiredDeckConfigCompatibility.length > 0 ? ( - - ) : null} + + + {i18n.format(t('deck_hardware'), 'capitalize')} + + + {t('location')} + + + {t('status')} + + + + {hasModules ? ( + + ) : null} + {requiredDeckConfigCompatibility.length > 0 ? ( + + ) : null} + ) : ( diff --git a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/utils.ts b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/utils.ts index 10bf9b5148d..c5ac5c7984e 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/utils.ts +++ b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/utils.ts @@ -1,5 +1,11 @@ import { + HEATERSHAKER_MODULE_V1_FIXTURE, + MAGNETIC_BLOCK_V1_FIXTURE, STAGING_AREA_RIGHT_SLOT_FIXTURE, + STAGING_AREA_SLOT_WITH_MAGNETIC_BLOCK_V1_FIXTURE, + TEMPERATURE_MODULE_V2_FIXTURE, + THERMOCYCLER_V2_FRONT_FIXTURE, + THERMOCYCLER_V2_REAR_FIXTURE, TRASH_BIN_ADAPTER_FIXTURE, WASTE_CHUTE_ONLY_FIXTURES, WASTE_CHUTE_STAGING_AREA_FIXTURES, @@ -11,6 +17,7 @@ import thermoModuleGen1 from '../../../../assets/images/thermocycler_closed.png' import heaterShakerModule from '../../../../assets/images/heater_shaker_module_transparent.png' import thermoModuleGen2 from '../../../../assets/images/thermocycler_gen_2_closed.png' import magneticBlockGen1 from '../../../../assets/images/magnetic_block_gen_1.png' +import stagingAreaMagneticBlockGen1 from '../../../../assets/images/staging_area_magnetic_block_gen_1.png' import trashBin from '../../../../assets/images/flex_trash_bin.png' import stagingArea from '../../../../assets/images/staging_area_slot.png' import wasteChute from '../../../../assets/images/waste_chute.png' @@ -48,6 +55,20 @@ export function getFixtureImage(cutoutFixtureId: CutoutFixtureId): string { return wasteChuteStagingArea } else if (cutoutFixtureId === TRASH_BIN_ADAPTER_FIXTURE) { return trashBin + } else if (cutoutFixtureId === THERMOCYCLER_V2_REAR_FIXTURE) { + return thermoModuleGen2 + } else if (cutoutFixtureId === THERMOCYCLER_V2_FRONT_FIXTURE) { + return thermoModuleGen2 + } else if (cutoutFixtureId === HEATERSHAKER_MODULE_V1_FIXTURE) { + return heaterShakerModule + } else if (cutoutFixtureId === TEMPERATURE_MODULE_V2_FIXTURE) { + return temperatureModule + } else if (cutoutFixtureId === MAGNETIC_BLOCK_V1_FIXTURE) { + return magneticBlockGen1 + } else if ( + cutoutFixtureId === STAGING_AREA_SLOT_WITH_MAGNETIC_BLOCK_V1_FIXTURE + ) { + return stagingAreaMagneticBlockGen1 } else { return 'Error: unknown fixture' } diff --git a/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunHeader.test.tsx b/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunHeader.test.tsx index 65ea98c906f..f7d1b09f80a 100644 --- a/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunHeader.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunHeader.test.tsx @@ -59,11 +59,7 @@ import { mockHeaterShaker } from '../../../../redux/modules/__fixtures__' import { useTrackEvent, ANALYTICS_PROTOCOL_PROCEED_TO_RUN, - ANALYTICS_PROTOCOL_RUN_AGAIN, - ANALYTICS_PROTOCOL_RUN_FINISH, - ANALYTICS_PROTOCOL_RUN_PAUSE, - ANALYTICS_PROTOCOL_RUN_START, - ANALYTICS_PROTOCOL_RUN_RESUME, + ANALYTICS_PROTOCOL_RUN_ACTION, } from '../../../../redux/analytics' import { mockConnectableRobot } from '../../../../redux/discovery/__fixtures__' import { getRobotUpdateDisplayInfo } from '../../../../redux/robot-update' @@ -427,7 +423,7 @@ describe('ProtocolRunHeader', () => { fireEvent.click(button) expect(mockTrackProtocolRunEvent).toBeCalledTimes(1) expect(mockTrackProtocolRunEvent).toBeCalledWith({ - name: ANALYTICS_PROTOCOL_RUN_START, + name: ANALYTICS_PROTOCOL_RUN_ACTION.START, properties: {}, }) }) @@ -445,7 +441,7 @@ describe('ProtocolRunHeader', () => { expect(mockCloseCurrentRun).toBeCalled() expect(mockTrackProtocolRunEvent).toBeCalled() expect(mockTrackProtocolRunEvent).toBeCalledWith({ - name: ANALYTICS_PROTOCOL_RUN_FINISH, + name: ANALYTICS_PROTOCOL_RUN_ACTION.FINISH, properties: {}, }) }) @@ -526,7 +522,7 @@ describe('ProtocolRunHeader', () => { screen.getByText('Protocol end') fireEvent.click(button) expect(mockTrackProtocolRunEvent).toBeCalledWith({ - name: ANALYTICS_PROTOCOL_RUN_PAUSE, + name: ANALYTICS_PROTOCOL_RUN_ACTION.PAUSE, }) }) @@ -564,7 +560,7 @@ describe('ProtocolRunHeader', () => { screen.getByText('Paused') fireEvent.click(button) expect(mockTrackProtocolRunEvent).toBeCalledWith({ - name: ANALYTICS_PROTOCOL_RUN_RESUME, + name: ANALYTICS_PROTOCOL_RUN_ACTION.RESUME, properties: {}, }) }) @@ -649,7 +645,7 @@ describe('ProtocolRunHeader', () => { screen.getByText(formatTimestamp(COMPLETED_AT)) fireEvent.click(button) expect(mockTrackProtocolRunEvent).toBeCalledWith({ - name: ANALYTICS_PROTOCOL_RUN_AGAIN, + name: ANALYTICS_PROTOCOL_RUN_ACTION.AGAIN, }) }) @@ -676,7 +672,7 @@ describe('ProtocolRunHeader', () => { screen.getByText(formatTimestamp(COMPLETED_AT)) fireEvent.click(button) expect(mockTrackProtocolRunEvent).toBeCalledWith({ - name: ANALYTICS_PROTOCOL_RUN_AGAIN, + name: ANALYTICS_PROTOCOL_RUN_ACTION.AGAIN, }) }) @@ -710,7 +706,7 @@ describe('ProtocolRunHeader', () => { }, }) expect(mockTrackProtocolRunEvent).toBeCalledWith({ - name: ANALYTICS_PROTOCOL_RUN_AGAIN, + name: ANALYTICS_PROTOCOL_RUN_ACTION.AGAIN, }) }) @@ -814,7 +810,7 @@ describe('ProtocolRunHeader', () => { screen.getByText('Run completed.') }) - it('clicking close on a terminal run banner closes the run context and dismisses the banner', async () => { + it('clicking close on a terminal run banner closes the run context', async () => { when(vi.mocked(useNotifyRunQuery)) .calledWith(RUN_ID) .thenReturn({ @@ -827,9 +823,20 @@ describe('ProtocolRunHeader', () => { fireEvent.click(screen.getByTestId('Banner_close-button')) expect(mockCloseCurrentRun).toBeCalled() - await waitFor(() => { - expect(screen.queryByText('Run completed.')).not.toBeInTheDocument() - }) + }) + + it('does not display the "run successful" banner if the successful run is not current', async () => { + when(vi.mocked(useNotifyRunQuery)) + .calledWith(RUN_ID) + .thenReturn({ + data: { data: { ...mockSucceededRun, current: false } }, + } as UseQueryResult) + when(vi.mocked(useRunStatus)) + .calledWith(RUN_ID) + .thenReturn(RUN_STATUS_SUCCEEDED) + render() + + expect(screen.queryByText('Run completed.')).not.toBeInTheDocument() }) it('if a heater shaker is shaking, clicking on start run should render HeaterShakerIsRunningModal', async () => { diff --git a/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunRuntimeParameters.test.tsx b/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunRuntimeParameters.test.tsx index f683986c26b..e2398fb084c 100644 --- a/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunRuntimeParameters.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunRuntimeParameters.test.tsx @@ -1,12 +1,17 @@ import * as React from 'react' +import { UseQueryResult } from 'react-query' import { describe, it, vi, beforeEach, afterEach, expect } from 'vitest' import { screen } from '@testing-library/react' import { when } from 'vitest-when' +import { Run } from '@opentrons/api-client' import { InfoScreen } from '@opentrons/components' import { renderWithProviders } from '../../../../__testing-utils__' import { i18n } from '../../../../i18n' import { useMostRecentCompletedAnalysis } from '../../../LabwarePositionCheck/useMostRecentCompletedAnalysis' +import { useRunStatus } from '../../../RunTimeControl/hooks' +import { useNotifyRunQuery } from '../../../../resources/runs' +import { mockSucceededRun } from '../../../RunTimeControl/__fixtures__' import { ProtocolRunRuntimeParameters } from '../ProtocolRunRunTimeParameters' @@ -23,6 +28,8 @@ vi.mock('@opentrons/components', async importOriginal => { } }) vi.mock('../../../LabwarePositionCheck/useMostRecentCompletedAnalysis') +vi.mock('../../../RunTimeControl/hooks') +vi.mock('../../../../resources/runs') const RUN_ID = 'mockId' @@ -100,13 +107,17 @@ describe('ProtocolRunRuntimeParameters', () => { .thenReturn({ runTimeParameters: mockRunTimeParameterData, } as CompletedProtocolAnalysis) + vi.mocked(useRunStatus).mockReturnValue('running') + vi.mocked(useNotifyRunQuery).mockReturnValue(({ + data: { data: mockSucceededRun }, + } as unknown) as UseQueryResult) }) afterEach(() => { vi.resetAllMocks() }) - it('should render title, and banner when RunTimeParameters are note empty and all values are default', () => { + it('should render title, and banner when RunTimeParameters are not empty and all values are default', () => { render(props) screen.getByText('Parameters') screen.getByText('Default values') @@ -116,7 +127,7 @@ describe('ProtocolRunRuntimeParameters', () => { screen.getByText('Value') }) - it('should render title, and banner when RunTimeParameters are note empty and some value is changed', () => { + it('should render title, and banner when RunTimeParameters are not empty and some value is changed', () => { vi.mocked(useMostRecentCompletedAnalysis).mockReturnValue({ runTimeParameters: [ ...mockRunTimeParameterData, @@ -139,7 +150,7 @@ describe('ProtocolRunRuntimeParameters', () => { screen.getByText('Value') }) - it('should render RunTimeParameters when RunTimeParameters are note empty', () => { + it('should render RunTimeParameters when RunTimeParameters are not empty', () => { render(props) screen.getByText('Dry Run') screen.getByText('Off') @@ -158,7 +169,7 @@ describe('ProtocolRunRuntimeParameters', () => { runTimeParameters: [] as RunTimeParameter[], } as CompletedProtocolAnalysis) render(props) - screen.getByText('Parameters') + expect(screen.queryByText('Parameters')).not.toBeInTheDocument() expect(screen.queryByText('Default values')).not.toBeInTheDocument() screen.getByText('mock InfoScreen') }) diff --git a/app/src/organisms/Devices/ProtocolRun/utils/__tests__/getLabwareRenderInfo.test.ts b/app/src/organisms/Devices/ProtocolRun/utils/__tests__/getLabwareRenderInfo.test.ts index f96bacc93b6..0da562e9549 100644 --- a/app/src/organisms/Devices/ProtocolRun/utils/__tests__/getLabwareRenderInfo.test.ts +++ b/app/src/organisms/Devices/ProtocolRun/utils/__tests__/getLabwareRenderInfo.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect } from 'vitest' -import { transfer_settings, ot2DeckDefV4 } from '@opentrons/shared-data' +import { transfer_settings, ot2DeckDefV5 } from '@opentrons/shared-data' import { getLabwareRenderInfo } from '../getLabwareRenderInfo' import type { CompletedProtocolAnalysis, @@ -8,7 +8,7 @@ import type { } from '@opentrons/shared-data' const protocolWithMagTempTC = (transfer_settings as unknown) as CompletedProtocolAnalysis -const standardDeckDef = ot2DeckDefV4 as any +const standardDeckDef = ot2DeckDefV5 as any describe('getLabwareRenderInfo', () => { it('should gather labware coordinates', () => { diff --git a/app/src/organisms/Devices/ProtocolRun/utils/__tests__/getProtocolModulesInfo.test.ts b/app/src/organisms/Devices/ProtocolRun/utils/__tests__/getProtocolModulesInfo.test.ts index cd6b5d06408..93528250b0d 100644 --- a/app/src/organisms/Devices/ProtocolRun/utils/__tests__/getProtocolModulesInfo.test.ts +++ b/app/src/organisms/Devices/ProtocolRun/utils/__tests__/getProtocolModulesInfo.test.ts @@ -2,7 +2,7 @@ import { describe, it, expect } from 'vitest' import { transfer_settings, multiple_temp_modules, - ot2DeckDefV4, + ot2DeckDefV5, getModuleDef2, ProtocolAnalysisOutput, LoadedLabware, @@ -174,7 +174,7 @@ const protocolWithMultipleTemps = ({ }, ] as LoadedModule[], } as unknown) as ProtocolAnalysisOutput -const standardDeckDef = ot2DeckDefV4 as any +const standardDeckDef = ot2DeckDefV5 as any describe('getProtocolModulesInfo', () => { it('should gather protocol module info for temp, mag, and tc', () => { diff --git a/app/src/organisms/Devices/RobotOverflowMenu.tsx b/app/src/organisms/Devices/RobotOverflowMenu.tsx index 751729b25a8..dd624e2dcd5 100644 --- a/app/src/organisms/Devices/RobotOverflowMenu.tsx +++ b/app/src/organisms/Devices/RobotOverflowMenu.tsx @@ -84,25 +84,27 @@ export function RobotOverflowMenu(props: RobotOverflowMenuProps): JSX.Element { if (robot.status === CONNECTABLE && runId == null) { menuItems = ( <> - {!isRobotBusy ? ( - - {t('run_a_protocol')} - - ) : null} + + {t('run_a_protocol')} + {isRobotOnWrongVersionOfSoftware && ( {t('shared:a_software_update_is_available')} )} + {!isRobotOnWrongVersionOfSoftware && isRobotBusy && ( + + {t('shared:robot_is_busy')} + + )} - {t('connection_lost_description')} + {t('branded:connection_lost_description')} void + robotName: string + sn: string | null +} + +interface FormValues { + factoryModeInput: string +} + +export function FactoryModeSlideout({ + isExpanded, + isRobotBusy, + onCloseClick, + robotName, + sn, +}: FactoryModeSlideoutProps): JSX.Element { + const { t } = useTranslation(['device_settings', 'shared', 'branded']) + + const dispatch = useDispatch() + + const { settings } = useRobotSettingsQuery().data ?? {} + const oemModeSetting = (settings ?? []).find( + (setting: RobotSettingsField) => setting?.id === 'enableOEMMode' + ) + const isOEMMode = oemModeSetting?.value ?? null + + const last = sn?.substring(sn.length - 4) + + const [currentStep, setCurrentStep] = React.useState(1) + const [toggleValue, setToggleValue] = React.useState(false) + const [file, setFile] = React.useState(null) + const [fileError, setFileError] = React.useState(null) + const [isUploading, setIsUploading] = React.useState(false) + + const onFinishCompleteClick = (): void => { + dispatch(restartRobot(robotName)) + onCloseClick() + setIsUploading(false) + } + + const { createSplash } = useCreateSplashMutation({ + onSuccess: () => { + onFinishCompleteClick() + }, + }) + + const { updateRobotSetting } = useUpdateRobotSettingMutation({ + onSuccess: () => { + if (toggleValue && file != null) { + createSplash({ file }) + } else { + onFinishCompleteClick() + } + }, + }) + + const validate = ( + data: FormValues, + errors: Record + ): Record => { + const factoryModeInput = data.factoryModeInput + let errorMessage: string | undefined + if (factoryModeInput !== last) { + errorMessage = t('invalid_password') + } + + const updatedErrors = + errorMessage != null + ? { + ...errors, + factoryModeInput: { + type: 'error', + message: errorMessage, + }, + } + : errors + return updatedErrors + } + + const resolver: Resolver = values => { + let errors = {} + errors = validate(values, errors) + return { values, errors } + } + + const { + clearErrors, + control, + formState: { errors }, + handleSubmit, + } = useForm({ + defaultValues: { + factoryModeInput: '', + }, + mode: 'onSubmit', + resolver, + reValidateMode: 'onSubmit', + }) + + const onSubmit = (): void => { + setCurrentStep(2) + } + + const handleSubmitFactoryPassword = (): void => { + void handleSubmit(onSubmit)() + } + + const handleToggleClick: React.MouseEventHandler = () => { + setToggleValue(toggleValue => !toggleValue) + } + + const handleCompleteClick: React.MouseEventHandler = () => { + setIsUploading(true) + updateRobotSetting({ id: 'enableOEMMode', value: toggleValue }) + } + + const handleChooseFile = (file: File): void => { + // validation for file type + if (file.type !== 'image/png') { + setFileError('Incorrect file type') + setFile(file) + } else { + const imgUrl = URL.createObjectURL(file) + const logoImage = new Image() + logoImage.src = imgUrl + logoImage.onload = () => { + // validation for ODD screen size + if ( + logoImage.naturalWidth !== 1024 || + logoImage.naturalHeight !== 600 + ) { + setFileError('Incorrect image dimensions') + } + setFile(file) + } + } + } + + React.useEffect(() => { + // initialize local state to OEM mode value + if (isOEMMode != null) { + setToggleValue(isOEMMode) + } + }, [isOEMMode]) + + return ( + + {currentStep === 1 ? ( + + {t('shared:next')} + + ) : null} + {currentStep === 2 ? ( + + {isUploading ? ( + + ) : ( + t('complete_and_restart_robot') + )} + + ) : null} + + } + > + {currentStep === 1 ? ( + + ( + ) => { + field.onChange(e) + clearErrors() + }} + value={field.value} + error={fieldState.error?.message && ' '} + onBlur={field.onBlur} + title={t('enter_factory_password')} + /> + )} + /> + {errors.factoryModeInput != null ? ( + + {errors.factoryModeInput.message} + + ) : null} + + ) : null} + {currentStep === 2 ? ( + + + + {t('oem_mode')} + + + + + {toggleValue ? t('on') : t('off')} + + + {t('branded:oem_mode_description')} + + {toggleValue ? ( + + + + {t('upload_custom_logo')} + + + {t('upload_custom_logo_description')} + + + {t('upload_custom_logo_dimensions')} + + + {file == null ? ( + handleChooseFile(file)} + dragAndDropText={ + + , + }} + /> + + } + /> + ) : ( + { + setFile(null) + setFileError(null) + }} + /> + )} + + ) : null} + + ) : null} + + ) +} diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/__tests__/DeviceResetModal.test.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/__tests__/DeviceResetModal.test.tsx index 63cfd490c51..b741f3ef5c8 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/__tests__/DeviceResetModal.test.tsx +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/__tests__/DeviceResetModal.test.tsx @@ -103,7 +103,7 @@ describe('RobotSettings DeviceResetModal', () => { }) screen.getByText('Connection to robot lost') screen.getByText( - 'The Opentrons App is unable to communicate with this robot right now. Double check the USB or Wifi connection to the robot, then try to reconnect.' + 'The Opentrons App is unable to communicate with this robot right now. Double check the USB or Wi-Fi connection to the robot, then try to reconnect.' ) screen.getByRole('button', { name: 'close' }) }) diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/FactoryMode.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/FactoryMode.tsx new file mode 100644 index 00000000000..3ca4f7cb7c1 --- /dev/null +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/FactoryMode.tsx @@ -0,0 +1,52 @@ +import * as React from 'react' +import { useTranslation } from 'react-i18next' + +import { + ALIGN_CENTER, + Box, + Flex, + JUSTIFY_SPACE_BETWEEN, + SPACING_AUTO, + SPACING, + StyledText, + TYPOGRAPHY, +} from '@opentrons/components' + +import { TertiaryButton } from '../../../../atoms/buttons' + +interface FactoryModeProps { + isRobotBusy: boolean + setShowFactoryModeSlideout: React.Dispatch> + sn: string | null +} + +export function FactoryMode({ + isRobotBusy, + setShowFactoryModeSlideout, + sn, +}: FactoryModeProps): JSX.Element { + const { t } = useTranslation('device_settings') + + return ( + + + + {t('factory_mode')} + + + { + setShowFactoryModeSlideout(true) + }} + > + {t('setup_mode')} + + + ) +} diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/RobotServerVersion.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/RobotServerVersion.tsx index 193b0e140b9..0be4e872ed4 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/RobotServerVersion.tsx +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/RobotServerVersion.tsx @@ -32,7 +32,7 @@ const GITHUB_LINK = export function RobotServerVersion({ robotName, }: RobotServerVersionProps): JSX.Element { - const { t } = useTranslation(['device_settings', 'shared']) + const { t } = useTranslation(['device_settings', 'shared', 'branded']) const robot = useRobot(robotName) const isFlex = useIsFlex(robotName) const { autoUpdateAction } = useSelector((state: State) => { @@ -65,7 +65,7 @@ export function RobotServerVersion({ {isFlex ? ( - {t('robot_server_version_ot3_description')} + {t('branded:robot_server_version_ot3_description')} ) : null} diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/SoftwareUpdateModal.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/SoftwareUpdateModal.tsx deleted file mode 100644 index 9884676e224..00000000000 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/SoftwareUpdateModal.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import * as React from 'react' -import { useTranslation } from 'react-i18next' -import { useSelector } from 'react-redux' -import { - DIRECTION_COLUMN, - Flex, - JUSTIFY_FLEX_END, - PrimaryButton, - SecondaryButton, - SPACING, - StyledText, - TYPOGRAPHY, -} from '@opentrons/components' -import { getShellUpdateState } from '../../../../redux/shell' -import { useCurrentRunId } from '../../../../organisms/ProtocolUpload/hooks' -// import { ReleaseNotes } from '../../../../molecules/ReleaseNotes' - -import { ExternalLink } from '../../../../atoms/Link/ExternalLink' -import { Banner } from '../../../../atoms/Banner' -import { LegacyModal } from '../../../../molecules/LegacyModal' -import { CONNECTABLE, REACHABLE } from '../../../../redux/discovery' -import { Divider } from '../../../../atoms/structure' -import { useRobot } from '../../hooks' -import { handleUpdateBuildroot } from '../UpdateBuildroot' - -const TECHNICAL_CHANGE_LOG_URL = - 'https://github.com/Opentrons/opentrons/blob/edge/CHANGELOG.md' -const ISSUE_TRACKER_URL = - 'https://github.com/Opentrons/opentrons/issues?q=is%3Aopen+is%3Aissue+label%3Abug' -const RELEASE_NOTES_URL = 'https://github.com/Opentrons/opentrons/releases' - -interface SoftwareUpdateModalProps { - robotName: string - closeModal: () => void -} - -export function SoftwareUpdateModal({ - robotName, - closeModal, -}: SoftwareUpdateModalProps): JSX.Element | null { - const { t } = useTranslation('device_settings') - - const currentRunId = useCurrentRunId() - // ToDo: Add release notes for the new design - const updateState = useSelector(getShellUpdateState) - // const { downloaded, downloading, error, info: updateInfo } = updateState - const { info: updateInfo } = updateState - const version = updateInfo?.version ?? '' - // const releaseNotes = updateInfo?.releaseNotes - const [showUpdateModal, setShowUpdateModal] = React.useState(false) - const robot = useRobot(robotName) - - if (robot?.status !== CONNECTABLE && robot?.status !== REACHABLE) return null - - return !showUpdateModal ? ( - - {t('requires_restarting_the_robot')} - - {/* ToDo: align with new design */} - - {t('app_change_in', { version })} - - - {'None in the Opentrons (Here will be change logs)'} - - - {t('new_features')} - - - {'None in the Opentrons (Here will be features info)'} - - - {t('bug_fixes')} - - - {'None in the Opentrons (Here will be fixes info)'} - - - - {t('view_opentrons_technical_change_log')} - - - {t('view_opentrons_issue_tracker')} - - - {t('view_opentrons_release_notes')} - - - - {t('remind_me_later')} - - { - setShowUpdateModal(true) - handleUpdateBuildroot(robot) - }} - disabled={currentRunId != null} - > - {t('update_robot_now')} - - - - - ) : null -} diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx index a8febac7092..bf7a27e389b 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx @@ -40,7 +40,7 @@ export function UpdateRobotSoftware({ onUpdateStart, isRobotBusy, }: UpdateRobotSoftwareProps): JSX.Element { - const { t } = useTranslation('device_settings') + const { t } = useTranslation(['device_settings', 'branded']) const { updateFromFileDisabledReason } = useSelector((state: State) => { return getRobotUpdateDisplayInfo(state, robotName) }) @@ -77,10 +77,10 @@ export function UpdateRobotSoftware({ {t('update_robot_software')} - {t('update_robot_software_description')} + {t('branded:update_robot_software_description')} - {t('update_robot_software_link')} + {t('branded:update_robot_software_link')}
() - const value = settings?.value ? settings.value : false - const id = settings?.id ? settings.id : 'disableFastProtocolUpload' - - const handleClick: React.MouseEventHandler = () => { - if (!isRobotBusy) { - dispatch(updateSetting(robotName, id, !value)) - } - } - - return ( - - - - {t('use_older_protocol_analysis_method')} - - - {t('use_older_protocol_analysis_method_description')} - - - - - ) -} diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/__tests__/SoftwareUpdateModal.test.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/__tests__/SoftwareUpdateModal.test.tsx deleted file mode 100644 index 141cc4b3638..00000000000 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/__tests__/SoftwareUpdateModal.test.tsx +++ /dev/null @@ -1,99 +0,0 @@ -/* eslint-disable testing-library/no-node-access */ -import * as React from 'react' -import { MemoryRouter } from 'react-router-dom' -import { screen } from '@testing-library/react' -import { describe, it, vi, beforeEach, expect } from 'vitest' -import '@testing-library/jest-dom/vitest' -import { renderWithProviders } from '../../../../../__testing-utils__' -import { i18n } from '../../../../../i18n' -import { getShellUpdateState } from '../../../../../redux/shell' -import { useRobot } from '../../../hooks' -import { mockReachableRobot } from '../../../../../redux/discovery/__fixtures__' - -import { SoftwareUpdateModal } from '../SoftwareUpdateModal' - -import type { ShellUpdateState } from '../../../../../redux/shell/types' -import type * as ShellUpdate from '../../../../../redux/shell/update' - -vi.mock('../../../../../redux/shell/update', async importOriginal => { - const actual = await importOriginal() - return { - ...actual, - getShellUpdateState: vi.fn(), - } -}) -vi.mock('../../../hooks') -vi.mock('../../../../../redux/discovery/selectors') - -const mockClose = vi.fn() - -const render = () => { - return renderWithProviders( - - - , - { i18nInstance: i18n } - ) -} - -describe('RobotSettings SoftwareUpdateModal', () => { - beforeEach(() => { - vi.mocked(useRobot).mockReturnValue(mockReachableRobot) - vi.mocked(getShellUpdateState).mockReturnValue({ - downloaded: true, - info: { - version: '1.2.3', - releaseNotes: 'this is a release', - }, - } as ShellUpdateState) - }) - - it('should render title ,description and button', () => { - render() - screen.getByText('Robot Update Available') - screen.getByText( - 'Updating the robot’s software requires restarting the robot' - ) - screen.getByText('App Changes in 1.2.3') - screen.getByText('New Features') - screen.getByText('Bug Fixes') - screen.getByText('View Opentrons technical change log') - screen.getByText('View Opentrons issue tracker') - screen.getByText('View full Opentrons release notes') - screen.getByRole('button', { name: 'Remind me later' }) - screen.getByRole('button', { name: 'Update robot now' }) - }) - - it('should have correct href', () => { - render() - const changeLogUrl = - 'https://github.com/Opentrons/opentrons/blob/edge/CHANGELOG.md' - const issueTrackerUrl = - 'https://github.com/Opentrons/opentrons/issues?q=is%3Aopen+is%3Aissue+label%3Abug' - const releaseNotesUrl = 'https://github.com/Opentrons/opentrons/releases' - - const linkForChangeLog = screen.getByRole('link', { - name: 'View Opentrons technical change log', - }) - expect(linkForChangeLog).toHaveAttribute('href', changeLogUrl) - - const linkForIssueTracker = screen.getByRole('link', { - name: 'View Opentrons issue tracker', - }) - expect(linkForIssueTracker.closest('a')).toHaveAttribute( - 'href', - issueTrackerUrl - ) - - const linkForReleaseNotes = screen.getByRole('link', { - name: 'View full Opentrons release notes', - }) - expect(linkForReleaseNotes.closest('a')).toHaveAttribute( - 'href', - releaseNotesUrl - ) - }) -}) diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/__tests__/UseOlderProtocol.test.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/__tests__/UseOlderProtocol.test.tsx deleted file mode 100644 index c2651ff8e1e..00000000000 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/__tests__/UseOlderProtocol.test.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import * as React from 'react' -import { MemoryRouter } from 'react-router-dom' -import { screen, fireEvent } from '@testing-library/react' -import { describe, it, vi, beforeEach, expect } from 'vitest' -import '@testing-library/jest-dom/vitest' -import { renderWithProviders } from '../../../../../__testing-utils__' - -import { i18n } from '../../../../../i18n' -import { getRobotSettings } from '../../../../../redux/robot-settings' - -import { UseOlderProtocol } from '../UseOlderProtocol' - -vi.mock('../../../../../redux/robot-settings/selectors') - -const mockSettings = { - id: 'disableFastProtocolUpload', - title: 'Use older protocol analysis method', - description: - 'Use an older, slower method of analyzing uploaded protocols. This changes how the OT-2 validates your protocol during the upload step, but does not affect how your protocol actually runs. Opentrons Support might ask you to change this setting if you encounter problems with the newer, faster protocol analysis method.', - value: true, - restart_required: false, -} - -const render = (isRobotBusy = false) => { - return renderWithProviders( - - - , - { i18nInstance: i18n } - ) -} - -describe('RobotSettings ShortTrashBin', () => { - beforeEach(() => { - vi.mocked(getRobotSettings).mockReturnValue([mockSettings]) - }) - - it('should render title, description and toggle button', () => { - render() - screen.getByText('Use older protocol analysis method') - screen.getByText( - 'Use an older, slower method of analyzing uploaded protocols. This changes how the OT-2 validates your protocol during the upload step, but does not affect how your protocol actually runs. Opentrons Support might ask you to change this setting if you encounter problems with the newer, faster protocol analysis method.' - ) - - const toggleButton = screen.getByRole('switch', { - name: 'use_older_protocol_analysis_method', - }) - expect(toggleButton.getAttribute('aria-checked')).toBe('true') - }) - - it('should change the value when a user clicks a toggle button', () => { - const tempMockSettings = { - ...mockSettings, - value: false, - } - vi.mocked(getRobotSettings).mockReturnValue([tempMockSettings]) - render() - const toggleButton = screen.getByRole('switch', { - name: 'use_older_protocol_analysis_method', - }) - fireEvent.click(toggleButton) - expect(toggleButton.getAttribute('aria-checked')).toBe('true') - }) - - it('should call update robot status if a robot is busy', () => { - render(true) - const toggleButton = screen.getByRole('switch', { - name: 'use_older_protocol_analysis_method', - }) - expect(toggleButton).toBeDisabled() - }) -}) diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/index.ts b/app/src/organisms/Devices/RobotSettings/AdvancedTab/index.ts index 1c5cb506bc7..e3359c3998b 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/index.ts +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/index.ts @@ -1,15 +1,14 @@ export * from './DeviceReset' export * from './DisplayRobotName' export * from './EnableStatusLight' +export * from './FactoryMode' export * from './GantryHoming' export * from './LegacySettings' export * from './OpenJupyterControl' export * from './RobotInformation' export * from './RobotServerVersion' export * from './ShortTrashBin' -export * from './SoftwareUpdateModal' export * from './Troubleshooting' export * from './UpdateRobotSoftware' export * from './UsageSettings' export * from './UseOlderAspirateBehavior' -export * from './UseOlderProtocol' diff --git a/app/src/organisms/Devices/RobotSettings/ConnectNetwork/DisconnectModal.tsx b/app/src/organisms/Devices/RobotSettings/ConnectNetwork/DisconnectModal.tsx index 660e04a1519..b489af43d1f 100644 --- a/app/src/organisms/Devices/RobotSettings/ConnectNetwork/DisconnectModal.tsx +++ b/app/src/organisms/Devices/RobotSettings/ConnectNetwork/DisconnectModal.tsx @@ -47,7 +47,7 @@ export const DisconnectModal = ({ onCancel, robotName, }: DisconnectModalProps): JSX.Element => { - const { t } = useTranslation(['device_settings', 'shared']) + const { t } = useTranslation(['device_settings', 'shared', 'branded']) const wifiList = useWifiList(robotName) const { wifi } = useSelector((state: State) => @@ -144,7 +144,7 @@ export const DisconnectModal = ({ {isError ? ( - {t('shared:general_error_message')} + {t('branded:general_error_message')} ) : null} diff --git a/app/src/organisms/Devices/RobotSettings/ConnectNetwork/__tests__/DisconnectModal.test.tsx b/app/src/organisms/Devices/RobotSettings/ConnectNetwork/__tests__/DisconnectModal.test.tsx index adf1e9a591a..79823d81ef3 100644 --- a/app/src/organisms/Devices/RobotSettings/ConnectNetwork/__tests__/DisconnectModal.test.tsx +++ b/app/src/organisms/Devices/RobotSettings/ConnectNetwork/__tests__/DisconnectModal.test.tsx @@ -160,7 +160,7 @@ describe('DisconnectModal', () => { 'Your robot was unable to disconnect from Wi-Fi network foo.' ) screen.getByText( - 'If you keep getting this message, try restarting your app and/or robot. If this does not resolve the issue please contact Opentrons Support.' + 'If you keep getting this message, try restarting your app and robot. If this does not resolve the issue, contact Opentrons Support.' ) screen.getByRole('button', { name: 'cancel' }) screen.getByRole('button', { name: 'Disconnect' }) diff --git a/app/src/organisms/Devices/RobotSettings/RobotSettingsAdvanced.tsx b/app/src/organisms/Devices/RobotSettings/RobotSettingsAdvanced.tsx index 8772f9a383a..418e8001269 100644 --- a/app/src/organisms/Devices/RobotSettings/RobotSettingsAdvanced.tsx +++ b/app/src/organisms/Devices/RobotSettings/RobotSettingsAdvanced.tsx @@ -19,6 +19,7 @@ import { DeviceReset, DisplayRobotName, EnableStatusLight, + FactoryMode, GantryHoming, LegacySettings, OpenJupyterControl, @@ -29,7 +30,6 @@ import { UpdateRobotSoftware, UsageSettings, UseOlderAspirateBehavior, - UseOlderProtocol, } from './AdvancedTab' import { updateSetting, @@ -39,8 +39,9 @@ import { import { RenameRobotSlideout } from './AdvancedTab/AdvancedTabSlideouts/RenameRobotSlideout' import { DeviceResetSlideout } from './AdvancedTab/AdvancedTabSlideouts/DeviceResetSlideout' import { DeviceResetModal } from './AdvancedTab/AdvancedTabSlideouts/DeviceResetModal' +import { FactoryModeSlideout } from './AdvancedTab/AdvancedTabSlideouts/FactoryModeSlideout' import { handleUpdateBuildroot } from './UpdateBuildroot' -import { UNREACHABLE } from '../../../redux/discovery' +import { getRobotSerialNumber, UNREACHABLE } from '../../../redux/discovery' import { getTopPortalEl } from '../../../App/portal' import { useIsEstopNotDisengaged } from '../../../resources/devices/hooks/useIsEstopNotDisengaged' @@ -72,6 +73,10 @@ export function RobotSettingsAdvanced({ showDeviceResetModal, setShowDeviceResetModal, ] = React.useState(false) + const [ + showFactoryModeSlideout, + setShowFactoryModeSlideout, + ] = React.useState(false) const isRobotBusy = useIsRobotBusy({ poll: true }) const isEstopNotDisengaged = useIsEstopNotDisengaged(robotName) @@ -83,6 +88,7 @@ export function RobotSettingsAdvanced({ getRobotSettings(state, robotName) ) const reachable = robot?.status !== UNREACHABLE + const sn = robot?.status != null ? getRobotSerialNumber(robot) : null const [isRobotReachable, setIsRobotReachable] = React.useState( reachable @@ -131,6 +137,15 @@ export function RobotSettingsAdvanced({ robotName={robotName} /> )} + {showFactoryModeSlideout && ( + setShowFactoryModeSlideout(false)} + robotName={robotName} + sn={sn} + /> + )} {showDeviceResetSlideout && ( handleUpdateBuildroot(robot)} /> + {isFlex ? ( + <> + + + + ) : null} {isFlex ? null : ( <> - - ((state: State) => getRobotSettings(state, robotName) ) diff --git a/app/src/organisms/Devices/RobotSettings/UpdateBuildroot/UpdateRobotModal.tsx b/app/src/organisms/Devices/RobotSettings/UpdateBuildroot/UpdateRobotModal.tsx index f02ad6ae3ce..4a1ffaec5ea 100644 --- a/app/src/organisms/Devices/RobotSettings/UpdateBuildroot/UpdateRobotModal.tsx +++ b/app/src/organisms/Devices/RobotSettings/UpdateBuildroot/UpdateRobotModal.tsx @@ -155,7 +155,7 @@ export function UpdateRobotModal({ > - {t('update_requires_restarting')} + {t('update_requires_restarting_robot')} diff --git a/app/src/organisms/Devices/RobotSettings/__tests__/RobotSettingsAdvanced.test.tsx b/app/src/organisms/Devices/RobotSettings/__tests__/RobotSettingsAdvanced.test.tsx index 0c39b924754..b373fb0565a 100644 --- a/app/src/organisms/Devices/RobotSettings/__tests__/RobotSettingsAdvanced.test.tsx +++ b/app/src/organisms/Devices/RobotSettings/__tests__/RobotSettingsAdvanced.test.tsx @@ -23,7 +23,6 @@ import { UpdateRobotSoftware, UsageSettings, UseOlderAspirateBehavior, - UseOlderProtocol, } from '../AdvancedTab' import { RobotSettingsAdvanced } from '../RobotSettingsAdvanced' @@ -53,7 +52,6 @@ vi.mock('../AdvancedTab/Troubleshooting') vi.mock('../AdvancedTab/UpdateRobotSoftware') vi.mock('../AdvancedTab/UsageSettings') vi.mock('../AdvancedTab/UseOlderAspirateBehavior') -vi.mock('../AdvancedTab/UseOlderProtocol') const mockUpdateRobotStatus = vi.fn() @@ -110,9 +108,6 @@ describe('RobotSettings Advanced tab', () => { vi.mocked(UseOlderAspirateBehavior).mockReturnValue(
Mock UseOlderAspirateBehavior Section
) - vi.mocked(UseOlderProtocol).mockReturnValue( -
Mock UseOlderProtocol Section
- ) when(useIsFlex).calledWith('otie').thenReturn(false) vi.mocked(EnableStatusLight).mockReturnValue(
mock EnableStatusLight
@@ -210,17 +205,6 @@ describe('RobotSettings Advanced tab', () => { ).toBeNull() }) - it('should render UseOlderProtocol section for OT-2', () => { - render() - screen.getByText('Mock UseOlderProtocol Section') - }) - - it('should not render UseOlderProtocol section for Flex', () => { - when(useIsFlex).calledWith('otie').thenReturn(true) - render() - expect(screen.queryByText('Mock UseOlderProtocol Section')).toBeNull() - }) - it('should not render EnableStatusLight section for OT-2', () => { render() expect(screen.queryByText('mock EnableStatusLight')).not.toBeInTheDocument() diff --git a/app/src/organisms/Devices/__tests__/HistoricalProtocolRun.test.tsx b/app/src/organisms/Devices/__tests__/HistoricalProtocolRun.test.tsx index bc59f8cf884..dccbb3dfefc 100644 --- a/app/src/organisms/Devices/__tests__/HistoricalProtocolRun.test.tsx +++ b/app/src/organisms/Devices/__tests__/HistoricalProtocolRun.test.tsx @@ -18,8 +18,8 @@ vi.mock('../../../redux/protocol-storage') vi.mock('../../RunTimeControl/hooks') vi.mock('../HistoricalProtocolRunOverflowMenu') vi.mock('react-router-dom', async importOriginal => { - const reactRouterDom = importOriginal() - return await { + const reactRouterDom = await importOriginal() + return { ...reactRouterDom, useHistory: () => ({ push: mockPush } as any), } diff --git a/app/src/organisms/Devices/__tests__/HistoricalProtocolRunOverflowMenu.test.tsx b/app/src/organisms/Devices/__tests__/HistoricalProtocolRunOverflowMenu.test.tsx index f7d537e88ff..c436bc04960 100644 --- a/app/src/organisms/Devices/__tests__/HistoricalProtocolRunOverflowMenu.test.tsx +++ b/app/src/organisms/Devices/__tests__/HistoricalProtocolRunOverflowMenu.test.tsx @@ -5,23 +5,24 @@ import '@testing-library/jest-dom/vitest' import { renderWithProviders } from '../../../__testing-utils__' import { when } from 'vitest-when' import { MemoryRouter } from 'react-router-dom' -import { UseQueryResult } from 'react-query' import { useAllCommandsQuery, useDeleteRunMutation, } from '@opentrons/react-api-client' import { i18n } from '../../../i18n' import runRecord from '../../../organisms/RunDetails/__fixtures__/runRecord.json' -import { useDownloadRunLog, useTrackProtocolRunEvent } from '../hooks' +import { useDownloadRunLog, useTrackProtocolRunEvent, useRobot } from '../hooks' import { useRunControls } from '../../RunTimeControl/hooks' import { useTrackEvent, ANALYTICS_PROTOCOL_PROCEED_TO_RUN, } from '../../../redux/analytics' +import { mockConnectableRobot } from '../../../redux/discovery/__fixtures__' import { getRobotUpdateDisplayInfo } from '../../../redux/robot-update' import { useIsEstopNotDisengaged } from '../../../resources/devices/hooks/useIsEstopNotDisengaged' import { HistoricalProtocolRunOverflowMenu } from '../HistoricalProtocolRunOverflowMenu' +import type { UseQueryResult } from 'react-query' import type { CommandsData } from '@opentrons/api-client' vi.mock('../../../redux/analytics') @@ -104,6 +105,9 @@ describe('HistoricalProtocolRunOverflowMenu', () => { robotName: ROBOT_NAME, robotIsBusy: false, } + when(vi.mocked(useRobot)) + .calledWith(ROBOT_NAME) + .thenReturn(mockConnectableRobot) }) it('renders the correct menu when a runId is present', () => { @@ -122,7 +126,10 @@ describe('HistoricalProtocolRunOverflowMenu', () => { fireEvent.click(rerunBtn) expect(mockTrackEvent).toHaveBeenCalledWith({ name: ANALYTICS_PROTOCOL_PROCEED_TO_RUN, - properties: { sourceLocation: 'HistoricalProtocolRun' }, + properties: { + robotSerialNumber: 'mock-serial', + sourceLocation: 'HistoricalProtocolRun', + }, }) expect(useRunControls).toHaveBeenCalled() expect(mockTrackProtocolRunEvent).toHaveBeenCalled() diff --git a/app/src/organisms/Devices/__tests__/InstrumentsAndModules.test.tsx b/app/src/organisms/Devices/__tests__/InstrumentsAndModules.test.tsx index 4c2774ea2bd..5b3e058b8fc 100644 --- a/app/src/organisms/Devices/__tests__/InstrumentsAndModules.test.tsx +++ b/app/src/organisms/Devices/__tests__/InstrumentsAndModules.test.tsx @@ -21,10 +21,7 @@ import { GripperCard } from '../../GripperCard' import { PipetteCard } from '../PipetteCard' import { FlexPipetteCard } from '../PipetteCard/FlexPipetteCard' import { PipetteRecalibrationWarning } from '../PipetteCard/PipetteRecalibrationWarning' -import { - getIs96ChannelPipetteAttached, - getShowPipetteCalibrationWarning, -} from '../utils' +import { getShowPipetteCalibrationWarning } from '../utils' import { useIsEstopNotDisengaged } from '../../../resources/devices/hooks/useIsEstopNotDisengaged' import type * as Components from '@opentrons/components' @@ -65,7 +62,6 @@ describe('InstrumentsAndModules', () => { isRunStill: true, isRunTerminal: false, }) - vi.mocked(getIs96ChannelPipetteAttached).mockReturnValue(false) vi.mocked(getShowPipetteCalibrationWarning).mockReturnValue(false) vi.mocked(useInstrumentsQuery).mockReturnValue({ data: { data: [] }, @@ -129,7 +125,20 @@ describe('InstrumentsAndModules', () => { }) it('renders 1 pipette card when a 96 channel is attached', () => { when(useIsFlex).calledWith(ROBOT_NAME).thenReturn(true) - vi.mocked(getIs96ChannelPipetteAttached).mockReturnValue(true) + vi.mocked(useInstrumentsQuery).mockReturnValue({ + data: { + data: [ + { + ok: true, + instrumentType: 'pipette', + mount: 'left', + data: { + channels: 96, + }, + }, + ], + }, + } as any) vi.mocked(useIsRobotViewable).mockReturnValue(true) render() expect(vi.mocked(FlexPipetteCard)).toHaveBeenCalledTimes(1) diff --git a/app/src/organisms/Devices/__tests__/RobotOverflowMenu.test.tsx b/app/src/organisms/Devices/__tests__/RobotOverflowMenu.test.tsx index 69ad5afc77a..6227cbd5675 100644 --- a/app/src/organisms/Devices/__tests__/RobotOverflowMenu.test.tsx +++ b/app/src/organisms/Devices/__tests__/RobotOverflowMenu.test.tsx @@ -20,6 +20,7 @@ vi.mock('../../../redux/robot-update/selectors') vi.mock('../../ProtocolUpload/hooks') vi.mock('../../ChooseProtocolSlideout') vi.mock('../hooks') +vi.mock('../../../resources/devices/hooks/useIsEstopNotDisengaged') const render = (props: React.ComponentProps) => { return renderWithProviders( @@ -85,19 +86,13 @@ describe('RobotOverflowMenu', () => { expect(run).toBeDisabled() }) - it('should only render robot settings when e-stop is pressed or disconnected', () => { + it('disables the run a protocol menu item if robot is busy', () => { vi.mocked(useCurrentRunId).mockReturnValue(null) - vi.mocked(getRobotUpdateDisplayInfo).mockReturnValue({ - autoUpdateAction: 'upgrade', - autoUpdateDisabledReason: null, - updateFromFileDisabledReason: null, - }) - vi.mocked(useIsRobotBusy).mockReturnValue(true) render(props) const btn = screen.getByLabelText('RobotOverflowMenu_button') fireEvent.click(btn) - expect(screen.queryByText('Run a protocol')).not.toBeInTheDocument() - screen.getByText('Robot settings') + const run = screen.getByText('Run a protocol') + expect(run).toBeDisabled() }) }) diff --git a/app/src/organisms/Devices/__tests__/RobotOverview.test.tsx b/app/src/organisms/Devices/__tests__/RobotOverview.test.tsx index b02e5ce600a..66f6d18b7d0 100644 --- a/app/src/organisms/Devices/__tests__/RobotOverview.test.tsx +++ b/app/src/organisms/Devices/__tests__/RobotOverview.test.tsx @@ -51,8 +51,8 @@ import type { State } from '../../../redux/types' import type * as ReactApiClient from '@opentrons/react-api-client' vi.mock('@opentrons/react-api-client', async importOriginal => { - const actual = importOriginal() - return await { + const actual = await importOriginal() + return { ...actual, useAuthorization: vi.fn(), } diff --git a/app/src/organisms/Devices/hooks/__tests__/useAttachedPipettesFromInstrumentsQuery.test.ts b/app/src/organisms/Devices/hooks/__tests__/useAttachedPipettesFromInstrumentsQuery.test.ts index 973e4837921..fbb72456a56 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useAttachedPipettesFromInstrumentsQuery.test.ts +++ b/app/src/organisms/Devices/hooks/__tests__/useAttachedPipettesFromInstrumentsQuery.test.ts @@ -1,16 +1,22 @@ import * as React from 'react' -import { vi, it, expect, describe } from 'vitest' +import { vi, it, expect, describe, beforeEach } from 'vitest' import { renderHook } from '@testing-library/react' import { useInstrumentsQuery } from '@opentrons/react-api-client' import { instrumentsResponseLeftPipetteFixture, instrumentsResponseRightPipetteFixture, } from '@opentrons/api-client' +import { useIsOEMMode } from '../../../../resources/robot-settings/hooks' import { useAttachedPipettesFromInstrumentsQuery } from '..' vi.mock('@opentrons/react-api-client') +vi.mock('../../../../resources/robot-settings/hooks') describe('useAttachedPipettesFromInstrumentsQuery hook', () => { + beforeEach(() => { + vi.mocked(useIsOEMMode).mockReturnValue(false) + }) + let wrapper: React.FunctionComponent<{ children: React.ReactNode }> it('returns attached pipettes', () => { vi.mocked(useInstrumentsQuery).mockReturnValue({ diff --git a/app/src/organisms/Devices/hooks/__tests__/useModuleRenderInfoForProtocolById.test.tsx b/app/src/organisms/Devices/hooks/__tests__/useModuleRenderInfoForProtocolById.test.tsx index 11b744f57a2..50381361b9a 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useModuleRenderInfoForProtocolById.test.tsx +++ b/app/src/organisms/Devices/hooks/__tests__/useModuleRenderInfoForProtocolById.test.tsx @@ -1,19 +1,18 @@ import { renderHook } from '@testing-library/react' import { vi, it, expect, describe, beforeEach } from 'vitest' import { when } from 'vitest-when' -import { UseQueryResult } from 'react-query' import { - STAGING_AREA_RIGHT_SLOT_FIXTURE, + TEMPERATURE_MODULE_TYPE, + TEMPERATURE_MODULE_V2, + TEMPERATURE_MODULE_V2_FIXTURE, heater_shaker_commands_with_results_key, } from '@opentrons/shared-data' import { useMostRecentCompletedAnalysis } from '../../../LabwarePositionCheck/useMostRecentCompletedAnalysis' -import { useDeckConfigurationQuery } from '@opentrons/react-api-client' import { getProtocolModulesInfo } from '../../ProtocolRun/utils/getProtocolModulesInfo' import { - mockMagneticModuleGen2, mockTemperatureModuleGen2, mockThermocycler, } from '../../../../redux/modules/__fixtures__' @@ -22,6 +21,7 @@ import { useModuleRenderInfoForProtocolById, useStoredProtocolAnalysis, } from '..' +import { useNotifyDeckConfigurationQuery } from '../../../../resources/deck_configuration' import type { CutoutConfig, @@ -30,12 +30,14 @@ import type { ModuleType, ProtocolAnalysisOutput, } from '@opentrons/shared-data' +import type { UseQueryResult } from 'react-query' +import type { AttachedModule } from '../../../../redux/modules/types' -vi.mock('@opentrons/react-api-client') vi.mock('../../ProtocolRun/utils/getProtocolModulesInfo') vi.mock('../useAttachedModules') vi.mock('../useStoredProtocolAnalysis') vi.mock('../../../LabwarePositionCheck/useMostRecentCompletedAnalysis') +vi.mock('../../../../resources/deck_configuration') const heaterShakerCommandsWithResultsKey = (heater_shaker_commands_with_results_key as unknown) as ProtocolAnalysisOutput @@ -53,25 +55,28 @@ const PROTOCOL_DETAILS = { protocolKey: 'fakeProtocolKey', } -const mockMagneticModuleDefinition = { - moduleId: 'someMagneticModule', - model: 'magneticModuleV2' as ModuleModel, - type: 'magneticModuleType' as ModuleType, - labwareOffset: { x: 5, y: 5, z: 5 }, - cornerOffsetFromSlot: { x: 1, y: 1, z: 1 }, - dimensions: { - xDimension: 100, - yDimension: 100, - footprintXDimension: 50, - footprintYDimension: 50, - labwareInterfaceXDimension: 80, - labwareInterfaceYDimension: 120, +const mockAttachedTempMod: AttachedModule = { + id: 'temp_mod_1', + moduleModel: TEMPERATURE_MODULE_V2, + moduleType: TEMPERATURE_MODULE_TYPE, + serialNumber: 'abc123', + hardwareRevision: 'heatershaker_v4.0', + firmwareVersion: 'v2.0.0', + hasAvailableUpdate: true, + data: { + currentTemperature: 40, + targetTemperature: null, + status: 'idle', + }, + usbPort: { + path: '/dev/ot_module_heatershaker0', + port: 1, + portGroup: 'unknown', + hub: false, }, - twoDimensionalRendering: { children: [] }, } const mockTemperatureModuleDefinition = { - moduleId: 'someMagneticModule', model: 'temperatureModuleV2' as ModuleModel, type: 'temperatureModuleType' as ModuleType, labwareOffset: { x: 5, y: 5, z: 5 }, @@ -87,19 +92,6 @@ const mockTemperatureModuleDefinition = { twoDimensionalRendering: { children: [] }, } -const MAGNETIC_MODULE_INFO = { - moduleId: 'magneticModuleId', - x: 0, - y: 0, - z: 0, - moduleDef: mockMagneticModuleDefinition as any, - nestedLabwareDef: null, - nestedLabwareId: null, - nestedLabwareDisplayName: null, - protocolLoadOrder: 0, - slotName: 'D1', -} - const TEMPERATURE_MODULE_INFO = { moduleId: 'temperatureModuleId', x: 0, @@ -111,20 +103,21 @@ const TEMPERATURE_MODULE_INFO = { nestedLabwareDisplayName: null, protocolLoadOrder: 0, slotName: 'D1', -} +} as any const mockCutoutConfig: CutoutConfig = { cutoutId: 'cutoutD1', - cutoutFixtureId: STAGING_AREA_RIGHT_SLOT_FIXTURE, + cutoutFixtureId: TEMPERATURE_MODULE_V2_FIXTURE, + opentronsModuleSerialNumber: 'abc123', } describe('useModuleRenderInfoForProtocolById hook', () => { beforeEach(() => { - vi.mocked(useDeckConfigurationQuery).mockReturnValue({ + vi.mocked(useNotifyDeckConfigurationQuery).mockReturnValue({ data: [mockCutoutConfig], } as UseQueryResult) + vi.mocked(useAttachedModules).mockReturnValue([mockAttachedTempMod]) vi.mocked(useAttachedModules).mockReturnValue([ - mockMagneticModuleGen2, mockTemperatureModuleGen2, mockThermocycler, ]) @@ -134,10 +127,7 @@ describe('useModuleRenderInfoForProtocolById hook', () => { when(vi.mocked(useMostRecentCompletedAnalysis)) .calledWith('1') .thenReturn(PROTOCOL_DETAILS.protocolData as any) - vi.mocked(getProtocolModulesInfo).mockReturnValue([ - TEMPERATURE_MODULE_INFO, - MAGNETIC_MODULE_INFO, - ]) + vi.mocked(getProtocolModulesInfo).mockReturnValue([TEMPERATURE_MODULE_INFO]) }) it('should return no module render info when protocol details not found', () => { @@ -155,13 +145,8 @@ describe('useModuleRenderInfoForProtocolById hook', () => { useModuleRenderInfoForProtocolById('1', true) ) expect(result.current).toStrictEqual({ - magneticModuleId: { - conflictedFixture: mockCutoutConfig, - attachedModuleMatch: mockMagneticModuleGen2, - ...MAGNETIC_MODULE_INFO, - }, temperatureModuleId: { - conflictedFixture: mockCutoutConfig, + conflictedFixture: null, attachedModuleMatch: mockTemperatureModuleGen2, ...TEMPERATURE_MODULE_INFO, }, diff --git a/app/src/organisms/Devices/hooks/__tests__/useProtocolRunAnalyticsData.test.tsx b/app/src/organisms/Devices/hooks/__tests__/useProtocolRunAnalyticsData.test.tsx index ce08a6cab90..f256fb126b7 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useProtocolRunAnalyticsData.test.tsx +++ b/app/src/organisms/Devices/hooks/__tests__/useProtocolRunAnalyticsData.test.tsx @@ -37,6 +37,16 @@ const MODULES = { module1: { model: 'module1' }, module2: { model: 'module2' }, } +const RUNTIME_PARAMETERS = [ + { + displayName: 'test param', + variableName: 'test_param', + description: 'Mock boolean parameter', + type: 'bool', + default: true, + value: true, + }, +] const FORMATTED_MODULES = 'module1,module2' const STORED_PROTOCOL_ANALYSIS = { config: { protocolType: 'json', schemaVersion: 1.11 }, @@ -49,11 +59,13 @@ const STORED_PROTOCOL_ANALYSIS = { robotType: 'OT-2 Standard', pipettes: PIPETTES, modules: MODULES, + runTimeParameters: RUNTIME_PARAMETERS, } const ROBOT_PROTOCOL_ANALYSIS = { robotType: 'OT-2 Standard', pipettes: PIPETTES, modules: MODULES, + runTimeParameters: RUNTIME_PARAMETERS, } describe('useProtocolAnalysisErrors hook', () => { @@ -126,12 +138,14 @@ describe('useProtocolAnalysisErrors hook', () => { protocolAppName: 'Python API', protocolAppVersion: 2.3, protocolAuthor: 'hashedString', + protocolHasRunTimeParameterCustomValues: false, + protocolHasRunTimeParameters: true, protocolName: 'robot protocol', protocolSource: 'robot protocol source', protocolText: 'hashedString', protocolType: '', robotType: 'OT-2 Standard', - robotSerialNumber: '', + robotSerialNumber: 'mock-serial', }, runTime: '1:00:00', }) @@ -156,11 +170,13 @@ describe('useProtocolAnalysisErrors hook', () => { protocolAppVersion: '1.1', protocolAuthor: 'hashedString', protocolName: 'stored protocol', + protocolHasRunTimeParameterCustomValues: false, + protocolHasRunTimeParameters: true, protocolSource: 'stored protocol source', protocolText: 'hashedString', protocolType: 'json', robotType: 'OT-2 Standard', - robotSerialNumber: '', + robotSerialNumber: 'mock-serial', }, runTime: '1:00:00', }) diff --git a/app/src/organisms/Devices/hooks/__tests__/useStoredProtocolAnalysis.test.tsx b/app/src/organisms/Devices/hooks/__tests__/useStoredProtocolAnalysis.test.tsx index fa63db104c6..4a165f628c5 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useStoredProtocolAnalysis.test.tsx +++ b/app/src/organisms/Devices/hooks/__tests__/useStoredProtocolAnalysis.test.tsx @@ -1,9 +1,9 @@ import * as React from 'react' import { vi, it, expect, describe, beforeEach, afterEach } from 'vitest' import { when } from 'vitest-when' -import { QueryClient, QueryClientProvider, UseQueryResult } from 'react-query' +import { QueryClient, QueryClientProvider } from 'react-query' import { Provider } from 'react-redux' -import { createStore, Store } from 'redux' +import { createStore } from 'redux' import { renderHook } from '@testing-library/react' import { @@ -12,12 +12,10 @@ import { parsePipetteEntity, } from '@opentrons/api-client' import { useProtocolQuery } from '@opentrons/react-api-client' +import { OT2_ROBOT_TYPE } from '@opentrons/shared-data' import { storedProtocolData } from '../../../../redux/protocol-storage/__fixtures__' -import { - getStoredProtocol, - StoredProtocolData, -} from '../../../../redux/protocol-storage' +import { getStoredProtocol } from '../../../../redux/protocol-storage' import { useStoredProtocolAnalysis } from '../useStoredProtocolAnalysis' import { LABWARE_ENTITY, @@ -27,7 +25,10 @@ import { } from '../__fixtures__/storedProtocolAnalysis' import { useNotifyRunQuery } from '../../../../resources/runs' +import type { Store } from 'redux' +import type { UseQueryResult } from 'react-query' import type { Protocol, Run } from '@opentrons/api-client' +import type { StoredProtocolData } from '../../../../redux/protocol-storage' vi.mock('@opentrons/api-client') vi.mock('@opentrons/react-api-client') @@ -44,6 +45,7 @@ const modifiedStoredProtocolData = { errors: storedProtocolData?.mostRecentAnalysis?.errors, runTimeParameters: storedProtocolData?.mostRecentAnalysis?.runTimeParameters, + robotType: OT2_ROBOT_TYPE, }, } diff --git a/app/src/organisms/Devices/hooks/__tests__/useTrackProtocolRunEvent.test.tsx b/app/src/organisms/Devices/hooks/__tests__/useTrackProtocolRunEvent.test.tsx index 3581dbdeee9..4642cf31557 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useTrackProtocolRunEvent.test.tsx +++ b/app/src/organisms/Devices/hooks/__tests__/useTrackProtocolRunEvent.test.tsx @@ -10,7 +10,7 @@ import { useTrackProtocolRunEvent } from '../useTrackProtocolRunEvent' import { useProtocolRunAnalyticsData } from '../useProtocolRunAnalyticsData' import { useTrackEvent, - ANALYTICS_PROTOCOL_RUN_START, + ANALYTICS_PROTOCOL_RUN_ACTION, } from '../../../../redux/analytics' import { mockConnectableRobot } from '../../../../redux/discovery/__fixtures__' import { useRobot } from '../useRobot' @@ -85,12 +85,12 @@ describe('useTrackProtocolRunEvent hook', () => { ) await waitFor(() => result.current.trackProtocolRunEvent({ - name: ANALYTICS_PROTOCOL_RUN_START, + name: ANALYTICS_PROTOCOL_RUN_ACTION.START, properties: {}, }) ) expect(mockTrackEvent).toHaveBeenCalledWith({ - name: ANALYTICS_PROTOCOL_RUN_START, + name: ANALYTICS_PROTOCOL_RUN_ACTION.START, properties: PROTOCOL_PROPERTIES, }) }) @@ -112,12 +112,12 @@ describe('useTrackProtocolRunEvent hook', () => { ) await waitFor(() => result.current.trackProtocolRunEvent({ - name: ANALYTICS_PROTOCOL_RUN_START, + name: ANALYTICS_PROTOCOL_RUN_ACTION.START, properties: {}, }) ) expect(mockTrackEvent).toHaveBeenCalledWith({ - name: ANALYTICS_PROTOCOL_RUN_START, + name: ANALYTICS_PROTOCOL_RUN_ACTION.START, properties: {}, }) }) diff --git a/app/src/organisms/Devices/hooks/useAttachedPipettesFromInstrumentsQuery.ts b/app/src/organisms/Devices/hooks/useAttachedPipettesFromInstrumentsQuery.ts index 770d71042fc..20427a60fbd 100644 --- a/app/src/organisms/Devices/hooks/useAttachedPipettesFromInstrumentsQuery.ts +++ b/app/src/organisms/Devices/hooks/useAttachedPipettesFromInstrumentsQuery.ts @@ -1,7 +1,10 @@ import { useInstrumentsQuery } from '@opentrons/react-api-client' -import { getPipetteModelSpecs, PipetteModel } from '@opentrons/shared-data' +import { LEFT, RIGHT } from '@opentrons/shared-data' +import { usePipetteModelSpecs } from '../../../resources/instruments/hooks' + import type { PipetteData } from '@opentrons/api-client' import type { Mount } from '@opentrons/components' +import type { PipetteModel } from '@opentrons/shared-data' export interface PipetteInformation extends PipetteData { displayName: string @@ -9,27 +12,32 @@ export interface PipetteInformation extends PipetteData { export type AttachedPipettesFromInstrumentsQuery = { [mount in Mount]: null | PipetteInformation } - export function useAttachedPipettesFromInstrumentsQuery(): AttachedPipettesFromInstrumentsQuery { - const { data: attachedInstruments } = useInstrumentsQuery() - return (attachedInstruments?.data ?? []).reduce( - (acc, instrumentData) => { - if (instrumentData.instrumentType !== 'pipette' || !instrumentData.ok) { - return acc - } - const { mount, instrumentModel } = instrumentData - return { - ...acc, - [mount as Mount]: { - ...instrumentData, - displayName: - instrumentModel != null - ? getPipetteModelSpecs(instrumentModel as PipetteModel) - ?.displayName ?? '' - : '', - }, - } - }, - { left: null, right: null } + const attachedInstruments = useInstrumentsQuery()?.data?.data ?? [] + + const okPipettes = attachedInstruments.filter( + (instrument): instrument is PipetteData => + instrument.instrumentType === 'pipette' && instrument.ok ) + + const leftPipette = okPipettes.find(({ mount }) => mount === LEFT) ?? null + const rightPipette = okPipettes.find(({ mount }) => mount === RIGHT) ?? null + + const leftDisplayName = + usePipetteModelSpecs(leftPipette?.instrumentModel as PipetteModel) + ?.displayName ?? '' + const rightDisplayName = + usePipetteModelSpecs(rightPipette?.instrumentModel as PipetteModel) + ?.displayName ?? '' + + return { + [LEFT]: + leftPipette != null + ? { ...leftPipette, displayName: leftDisplayName } + : null, + [RIGHT]: + rightPipette != null + ? { ...rightPipette, displayName: rightDisplayName } + : null, + } } diff --git a/app/src/organisms/Devices/hooks/useLastRunCommandKey.ts b/app/src/organisms/Devices/hooks/useLastRunCommand.ts similarity index 84% rename from app/src/organisms/Devices/hooks/useLastRunCommandKey.ts rename to app/src/organisms/Devices/hooks/useLastRunCommand.ts index b51160abf2d..347532abd36 100644 --- a/app/src/organisms/Devices/hooks/useLastRunCommandKey.ts +++ b/app/src/organisms/Devices/hooks/useLastRunCommand.ts @@ -12,7 +12,7 @@ import { } from '@opentrons/api-client' import type { UseQueryOptions } from 'react-query' -import type { CommandsData } from '@opentrons/api-client' +import type { CommandsData, RunCommandSummary } from '@opentrons/api-client' const LIVE_RUN_STATUSES = [ RUN_STATUS_IDLE, @@ -26,10 +26,10 @@ const LIVE_RUN_STATUSES = [ ] const LIVE_RUN_COMMANDS_POLL_MS = 3000 -export function useLastRunCommandKey( +export function useLastRunCommand( runId: string, options: UseQueryOptions = {} -): string | null { +): RunCommandSummary | null { const runStatus = useRunStatus(runId) const { data: commandsData } = useAllCommandsQuery( runId, @@ -44,8 +44,6 @@ export function useLastRunCommandKey( ) return commandsData?.data?.[0]?.intent !== 'setup' - ? commandsData?.links?.current?.meta?.key ?? - commandsData?.data?.[0]?.key ?? - null + ? commandsData?.data?.[0] ?? null : null } diff --git a/app/src/organisms/Devices/hooks/useModuleRenderInfoForProtocolById.ts b/app/src/organisms/Devices/hooks/useModuleRenderInfoForProtocolById.ts index 6ca57b24c4a..0190a3702dd 100644 --- a/app/src/organisms/Devices/hooks/useModuleRenderInfoForProtocolById.ts +++ b/app/src/organisms/Devices/hooks/useModuleRenderInfoForProtocolById.ts @@ -1,19 +1,17 @@ import { checkModuleCompatibility, FLEX_ROBOT_TYPE, - getCutoutIdForSlotName, + getCutoutFixturesForModuleModel, + getCutoutIdsFromModuleSlotName, getDeckDefFromRobotType, - MAGNETIC_BLOCK_TYPE, - SINGLE_SLOT_FIXTURES, - STAGING_AREA_RIGHT_SLOT_FIXTURE, - THERMOCYCLER_MODULE_TYPE, + OT2_ROBOT_TYPE, } from '@opentrons/shared-data' -import { useDeckConfigurationQuery } from '@opentrons/react-api-client' import { getProtocolModulesInfo } from '../ProtocolRun/utils/getProtocolModulesInfo' import { useMostRecentCompletedAnalysis } from '../../LabwarePositionCheck/useMostRecentCompletedAnalysis' import { useAttachedModules } from './useAttachedModules' import { useStoredProtocolAnalysis } from './useStoredProtocolAnalysis' +import { useNotifyDeckConfigurationQuery } from '../../../resources/deck_configuration' import type { CutoutConfig } from '@opentrons/shared-data' import type { AttachedModule } from '../../../redux/modules/types' @@ -35,7 +33,7 @@ export function useModuleRenderInfoForProtocolById( pollModules?: boolean ): ModuleRenderInfoById { const robotProtocolAnalysis = useMostRecentCompletedAnalysis(runId) - const { data: deckConfig } = useDeckConfigurationQuery({ + const { data: deckConfig = [] } = useNotifyDeckConfigurationQuery({ refetchInterval: REFETCH_INTERVAL_5000_MS, }) const storedProtocolAnalysis = useStoredProtocolAnalysis(runId) @@ -45,50 +43,57 @@ export function useModuleRenderInfoForProtocolById( }) if (protocolAnalysis == null) return {} - const deckDef = getDeckDefFromRobotType( - protocolAnalysis.robotType ?? FLEX_ROBOT_TYPE - ) + const assumedRobotType = protocolAnalysis.robotType ?? FLEX_ROBOT_TYPE + const deckDef = getDeckDefFromRobotType(assumedRobotType) const protocolModulesInfo = getProtocolModulesInfo(protocolAnalysis, deckDef) const protocolModulesInfoInLoadOrder = protocolModulesInfo.sort( (modA, modB) => modA.protocolLoadOrder - modB.protocolLoadOrder ) + + const robotSupportsModuleConfig = assumedRobotType !== OT2_ROBOT_TYPE let matchedAmod: AttachedModule[] = [] const allModuleRenderInfo = protocolModulesInfoInLoadOrder.map( protocolMod => { + const moduleFixtures = getCutoutFixturesForModuleModel( + protocolMod.moduleDef.model, + deckDef + ) + const moduleCutoutIds = getCutoutIdsFromModuleSlotName( + protocolMod.slotName, + moduleFixtures, + deckDef + ) const compatibleAttachedModule = attachedModules.find( attachedMod => + // first check module model compatibility checkModuleCompatibility( attachedMod.moduleModel, protocolMod.moduleDef.model - ) && !matchedAmod.find(m => m === attachedMod) + ) && + // then check that the module hasn't already been matched + !matchedAmod.some( + m => m.serialNumber === attachedMod.serialNumber + ) && + // then if robotType supports configurable modules check the deck config has a + // a module with the expected serial number in the expected location + (!robotSupportsModuleConfig || + deckConfig.some( + ({ cutoutId, opentronsModuleSerialNumber }) => + attachedMod.serialNumber === opentronsModuleSerialNumber && + moduleCutoutIds.includes(cutoutId) + )) ) ?? null - const cutoutIdForSlotName = getCutoutIdForSlotName( - protocolMod.slotName, - deckDef - ) - - const isMagneticBlockModule = - protocolMod.moduleDef.moduleType === MAGNETIC_BLOCK_TYPE - - const isThermocycler = - protocolMod.moduleDef.moduleType === THERMOCYCLER_MODULE_TYPE - const conflictedFixture = deckConfig?.find( - fixture => - (fixture.cutoutId === cutoutIdForSlotName || - // special-case A1 for the thermocycler to require a single slot fixture - (isThermocycler && fixture.cutoutId === 'cutoutA1')) && - fixture.cutoutFixtureId != null && - // do not generate a conflict for single slot fixtures, because modules are not yet fixtures - !SINGLE_SLOT_FIXTURES.includes(fixture.cutoutFixtureId) && - // special case the magnetic module because unlike other modules it sits in a slot that can also be provided by a staging area fixture - (!isMagneticBlockModule || - fixture.cutoutFixtureId !== STAGING_AREA_RIGHT_SLOT_FIXTURE) + ({ cutoutId, cutoutFixtureId }) => + moduleCutoutIds.includes(cutoutId) && + !moduleFixtures.some(({ id }) => cutoutFixtureId === id) && + // if robotType supports module config, don't treat module fixture as conflict + (!robotSupportsModuleConfig || compatibleAttachedModule == null) ) ?? null if (compatibleAttachedModule !== null) { diff --git a/app/src/organisms/Devices/hooks/useProtocolRunAnalyticsData.ts b/app/src/organisms/Devices/hooks/useProtocolRunAnalyticsData.ts index 93dde4bfefa..538c10c6855 100644 --- a/app/src/organisms/Devices/hooks/useProtocolRunAnalyticsData.ts +++ b/app/src/organisms/Devices/hooks/useProtocolRunAnalyticsData.ts @@ -51,6 +51,14 @@ export const parseProtocolRunAnalyticsData = ( .join(','), protocolAuthor: protocolAuthor !== '' ? protocolAuthor : '', protocolText: protocolText !== '' ? protocolText : '', + protocolHasRunTimeParameters: + protocolAnalysis?.runTimeParameters != null + ? protocolAnalysis?.runTimeParameters?.length > 0 + : false, + protocolHasRunTimeParameterCustomValues: + protocolAnalysis?.runTimeParameters?.some( + param => param.value !== param.default + ) ?? false, robotType: protocolAnalysis?.robotType != null ? protocolAnalysis?.robotType diff --git a/app/src/organisms/Devices/hooks/useRunStatuses.ts b/app/src/organisms/Devices/hooks/useRunStatuses.ts index bba83f76299..887de586f8e 100644 --- a/app/src/organisms/Devices/hooks/useRunStatuses.ts +++ b/app/src/organisms/Devices/hooks/useRunStatuses.ts @@ -1,15 +1,15 @@ import { + RUN_STATUSES_TERMINAL, RUN_STATUS_AWAITING_RECOVERY, - RUN_STATUS_FAILED, RUN_STATUS_IDLE, RUN_STATUS_PAUSED, RUN_STATUS_RUNNING, - RUN_STATUS_STOPPED, - RUN_STATUS_SUCCEEDED, } from '@opentrons/api-client' import { useCurrentRunId } from '../../ProtocolUpload/hooks' import { useRunStatus } from '../../RunTimeControl/hooks' +import type { RunStatus } from '@opentrons/api-client' + interface RunStatusesInfo { isRunStill: boolean isRunTerminal: boolean @@ -29,9 +29,9 @@ export function useRunStatuses(): RunStatusesInfo { runStatus === RUN_STATUS_RUNNING || runStatus === RUN_STATUS_AWAITING_RECOVERY const isRunTerminal = - runStatus === RUN_STATUS_SUCCEEDED || - runStatus === RUN_STATUS_STOPPED || - runStatus === RUN_STATUS_FAILED + runStatus != null + ? (RUN_STATUSES_TERMINAL as RunStatus[]).includes(runStatus) + : false const isRunStill = isRunTerminal || isRunIdle return { isRunStill, isRunTerminal, isRunIdle, isRunRunning } diff --git a/app/src/organisms/Devices/utils.ts b/app/src/organisms/Devices/utils.ts index a4d72e0d279..61c133f176b 100644 --- a/app/src/organisms/Devices/utils.ts +++ b/app/src/organisms/Devices/utils.ts @@ -9,7 +9,9 @@ import type { Instruments, PipetteData, PipetteOffsetCalibration, + RunTimeParameterCreateData, } from '@opentrons/api-client' +import type { RunTimeParameter } from '@opentrons/shared-data' /** * formats a string if it is in ISO 8601 date format @@ -89,3 +91,15 @@ export function getShowPipetteCalibrationWarning( }) ?? false ) } + +export function getRunTimeParameterValuesForRun( + runTimeParameters: RunTimeParameter[] +): RunTimeParameterCreateData { + return runTimeParameters.reduce( + (acc, param) => + param.value !== param.default + ? { ...acc, [param.variableName]: param.value } + : acc, + {} + ) +} diff --git a/app/src/organisms/DropTipWizard/BeforeBeginning.tsx b/app/src/organisms/DropTipWizard/BeforeBeginning.tsx index 69a8d7de694..cd21cc3e1a4 100644 --- a/app/src/organisms/DropTipWizard/BeforeBeginning.tsx +++ b/app/src/organisms/DropTipWizard/BeforeBeginning.tsx @@ -24,30 +24,20 @@ import { import { SmallButton, MediumButton } from '../../atoms/buttons' import { InProgressModal } from '../../molecules/InProgressModal/InProgressModal' -// import { NeedHelpLink } from '../CalibrationPanels' import blowoutVideo from '../../assets/videos/droptip-wizard/Blowout-Liquid.webm' import droptipVideo from '../../assets/videos/droptip-wizard/Drop-tip.webm' -// TODO: get help link article URL -// const NEED_HELP_URL = '' - interface BeforeBeginningProps { setShouldDispenseLiquid: (shouldDispenseLiquid: boolean) => void createdMaintenanceRunId: string | null isOnDevice: boolean - isRobotMoving: boolean } export const BeforeBeginning = ( props: BeforeBeginningProps ): JSX.Element | null => { - const { - setShouldDispenseLiquid, - createdMaintenanceRunId, - isOnDevice, - isRobotMoving, - } = props + const { setShouldDispenseLiquid, createdMaintenanceRunId, isOnDevice } = props const { i18n, t } = useTranslation(['drop_tip_wizard', 'shared']) const [flowType, setFlowType] = React.useState< 'liquid_and_tips' | 'only_tips' | null @@ -57,16 +47,8 @@ export const BeforeBeginning = ( setShouldDispenseLiquid(flowType === 'liquid_and_tips') } - if (isRobotMoving || createdMaintenanceRunId == null) { - return ( - - ) + if (createdMaintenanceRunId == null) { + return } if (isOnDevice) { diff --git a/app/src/organisms/DropTipWizard/ChooseLocation.tsx b/app/src/organisms/DropTipWizard/ChooseLocation.tsx index 8050c776698..7a86da67223 100644 --- a/app/src/organisms/DropTipWizard/ChooseLocation.tsx +++ b/app/src/organisms/DropTipWizard/ChooseLocation.tsx @@ -22,15 +22,13 @@ import { import { getDeckDefFromRobotType } from '@opentrons/shared-data' import { SmallButton } from '../../atoms/buttons' -import { InProgressModal } from '../../molecules/InProgressModal/InProgressModal' -// import { NeedHelpLink } from '../CalibrationPanels' import { TwoUpTileLayout } from '../LabwarePositionCheck/TwoUpTileLayout' import type { CommandData } from '@opentrons/api-client' import type { AddressableAreaName, RobotType } from '@opentrons/shared-data' +import type { ErrorDetails } from './utils' // TODO: get help link article URL -// const NEED_HELP_URL = '' interface ChooseLocationProps { handleProceed: () => void @@ -41,9 +39,8 @@ interface ChooseLocationProps { moveToAddressableArea: ( addressableArea: AddressableAreaName ) => Promise - isRobotMoving: boolean isOnDevice: boolean - setErrorMessage: (arg0: string) => void + setErrorDetails: (errorDetails: ErrorDetails) => void } export const ChooseLocation = ( @@ -56,9 +53,8 @@ export const ChooseLocation = ( body, robotType, moveToAddressableArea, - isRobotMoving, isOnDevice, - setErrorMessage, + setErrorDetails, } = props const { i18n, t } = useTranslation(['drop_tip_wizard', 'shared']) const deckDef = getDeckDefFromRobotType(robotType) @@ -74,14 +70,10 @@ export const ChooseLocation = ( if (deckSlot != null) { moveToAddressableArea(deckSlot) .then(() => handleProceed()) - .catch(e => setErrorMessage(`${e.message}`)) + .catch(e => setErrorDetails({ message: `${e.message}` })) } } - if (isRobotMoving) { - return - } - if (isOnDevice) { return ( void handleGoBack: () => void - isRobotMoving: boolean } export function ExitConfirmation(props: ExitConfirmationProps): JSX.Element { - const { handleGoBack, handleExit, isRobotMoving } = props + const { handleGoBack, handleExit } = props const { i18n, t } = useTranslation(['drop_tip_wizard', 'shared']) const flowTitle = t('drop_tips') const isOnDevice = useSelector(getIsOnDevice) - if (isRobotMoving) { - return - } - return ( void body: string - isRobotMoving: boolean currentStep: string isOnDevice: boolean } @@ -161,7 +160,6 @@ export const JogToPosition = ( handleJog, handleProceed, body, - isRobotMoving, currentStep, isOnDevice, } = props @@ -171,10 +169,10 @@ export const JogToPosition = ( setShowPositionConfirmation, ] = React.useState(false) // Includes special case homing only present in this step. - const [isRobotInMotion, setIsRobotInMotion] = React.useState(isRobotMoving) + const [isRobotInMotion, setIsRobotInMotion] = React.useState(false) const onGoBack = (): void => { - setIsRobotInMotion(() => true) + setIsRobotInMotion(true) handleGoBack() } @@ -201,11 +199,6 @@ export const JogToPosition = ( ) } - // Moving due to "Exit" or "Go back" click. - if (isRobotInMotion) { - return - } - if (isOnDevice) { return ( { describe('TipsAttachedModal', () => { beforeEach(() => { - vi.mocked(useNotifyCurrentMaintenanceRun).mockReturnValue({ - data: { - data: { - id: 'test', - }, - }, + vi.mocked(useCloseCurrentRun).mockReturnValue({ + closeCurrentRun: vi.fn(), } as any) }) diff --git a/app/src/organisms/DropTipWizard/__tests__/utils.test.tsx b/app/src/organisms/DropTipWizard/__tests__/utils.test.tsx new file mode 100644 index 00000000000..2cd6c415ba9 --- /dev/null +++ b/app/src/organisms/DropTipWizard/__tests__/utils.test.tsx @@ -0,0 +1,131 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest' +import { screen, render, fireEvent } from '@testing-library/react' + +import { useDropTipErrorComponents, useWizardExitHeader } from '../utils' +import { DROP_TIP_SPECIAL_ERROR_TYPES } from '../constants' + +import type { Mock } from 'vitest' +import type { + UseDropTipErrorComponentsProps, + UseWizardExitHeaderProps, +} from '../utils' + +const MOCK_MAINTENANCE_RUN_ID = 'MOCK_MAINTENANCE_RUN_ID' +const MOCK_ERROR_TYPE = 'MOCK_ERROR_TYPE' +const MOCK_ERROR_MESSAGE = 'MOCK_ERROR_MESSAGE' +const MOCK_ERROR_HEADER = 'MOCK_ERROR_HEADER' + +describe('useDropTipErrorComponents', () => { + let props: UseDropTipErrorComponentsProps + let mockOnClose: Mock + let mockTranslation: Mock + let mockChainRunCommands: Mock + + beforeEach(() => { + mockOnClose = vi.fn() + mockTranslation = vi.fn() + mockChainRunCommands = vi.fn() + + props = { + maintenanceRunId: MOCK_MAINTENANCE_RUN_ID, + onClose: mockOnClose, + errorDetails: { + type: MOCK_ERROR_TYPE, + message: MOCK_ERROR_MESSAGE, + header: MOCK_ERROR_HEADER, + }, + isOnDevice: true, + t: mockTranslation, + chainRunCommands: mockChainRunCommands, + } + }) + + it('should return the generic text and error message if there is are no special-cased error details', () => { + const result = useDropTipErrorComponents(props) + expect(result.button).toBeNull() + render(result.subHeader) + expect(mockTranslation).toHaveBeenCalledWith('drop_tip_failed') + screen.getByText(MOCK_ERROR_MESSAGE) + }) + + it('should return a generic message only if there are no error details', () => { + props.errorDetails = null + const result = useDropTipErrorComponents(props) + expect(result.button).toBeNull() + render(result.subHeader) + expect(mockTranslation).toHaveBeenCalledWith('drop_tip_failed') + expect(screen.queryByText(MOCK_ERROR_MESSAGE)).not.toBeInTheDocument() + }) + + it(`should return correct special components if error type is ${DROP_TIP_SPECIAL_ERROR_TYPES.MUST_HOME_ERROR}`, () => { + // @ts-expect-error errorDetails is in fact not null in the test. + props.errorDetails.type = DROP_TIP_SPECIAL_ERROR_TYPES.MUST_HOME_ERROR + const result = useDropTipErrorComponents(props) + expect(mockTranslation).toHaveBeenCalledWith('confirm_removal_and_home') + + render(result.button) + const btn = screen.getByRole('button') + fireEvent.click(btn) + expect(mockOnClose).toHaveBeenCalled() + expect(mockChainRunCommands).toHaveBeenCalledWith( + MOCK_MAINTENANCE_RUN_ID, + [ + { + commandType: 'home' as const, + params: {}, + }, + ], + true + ) + + render(result.subHeader) + screen.getByText(MOCK_ERROR_MESSAGE) + }) +}) + +describe('useWizardExitHeader', () => { + let props: UseWizardExitHeaderProps + let mockHandleCleanUpAndClose: Mock + let mockConfirmExit: Mock + + beforeEach(() => { + mockHandleCleanUpAndClose = vi.fn() + mockConfirmExit = vi.fn() + + props = { + isFinalStep: true, + hasInitiatedExit: false, + errorDetails: null, + handleCleanUpAndClose: mockHandleCleanUpAndClose, + confirmExit: mockConfirmExit, + } + }) + + it('should appropriately return handleCleanUpAndClose', () => { + const handleExit = useWizardExitHeader(props) + expect(handleExit).toEqual(props.handleCleanUpAndClose) + }) + + it('should appropriately return confirmExit', () => { + props = { ...props, isFinalStep: false } + const handleExit = useWizardExitHeader(props) + expect(handleExit).toEqual(props.confirmExit) + }) + + it('should appropriately return handleCleanUpAndClose with homeOnError = false', () => { + const errorDetails = { message: 'Some error occurred' } + const modifiedProps = { ...props, errorDetails } + const handleExit = useWizardExitHeader(modifiedProps) + expect(mockHandleCleanUpAndClose.mock.calls.length).toBe(0) + handleExit() + expect(mockHandleCleanUpAndClose).toHaveBeenCalledWith(false) + }) + + it('should appropriately return a function that does nothing ', () => { + const modifiedProps = { ...props, hasInitiatedExit: true } + const handleExit = useWizardExitHeader(modifiedProps) + handleExit() + expect(mockHandleCleanUpAndClose.mock.calls.length).toBe(0) + expect(mockConfirmExit.mock.calls.length).toBe(0) + }) +}) diff --git a/app/src/organisms/DropTipWizard/constants.ts b/app/src/organisms/DropTipWizard/constants.ts index 0390fd1870f..6d322f779ec 100644 --- a/app/src/organisms/DropTipWizard/constants.ts +++ b/app/src/organisms/DropTipWizard/constants.ts @@ -16,3 +16,7 @@ export const DROP_TIP_STEPS = [ POSITION_AND_DROP_TIP, DROP_TIP_SUCCESS, ] + +export const DROP_TIP_SPECIAL_ERROR_TYPES = { + MUST_HOME_ERROR: 'MustHomeError', +} as const diff --git a/app/src/organisms/DropTipWizard/getAddressableAreaFromConfig.ts b/app/src/organisms/DropTipWizard/getAddressableAreaFromConfig.ts index 021b84ccc09..7f9ccda9c52 100644 --- a/app/src/organisms/DropTipWizard/getAddressableAreaFromConfig.ts +++ b/app/src/organisms/DropTipWizard/getAddressableAreaFromConfig.ts @@ -1,5 +1,6 @@ import { EIGHT_CHANNEL_WASTE_CHUTE_ADDRESSABLE_AREA, + FLEX_MODULE_ADDRESSABLE_AREAS, getCutoutIdForAddressableArea, getDeckDefFromRobotType, MOVABLE_TRASH_ADDRESSABLE_AREAS, @@ -46,9 +47,11 @@ export function getAddressableAreaFromConfig( if (providedAddressableAreas.includes(addressableArea)) { addressableAreaFromConfig = addressableArea } else if ( - // if no, check if provides a movable trash - providedAddressableAreas.some(aa => - MOVABLE_TRASH_ADDRESSABLE_AREAS.includes(aa) + // if no, check if provides a movable trash or module fixture + providedAddressableAreas.some( + aa => + MOVABLE_TRASH_ADDRESSABLE_AREAS.includes(aa) || + FLEX_MODULE_ADDRESSABLE_AREAS.includes(aa) ) ) { addressableAreaFromConfig = providedAddressableAreas[0] diff --git a/app/src/organisms/DropTipWizard/index.tsx b/app/src/organisms/DropTipWizard/index.tsx index 3d7896663d4..bd55591e1da 100644 --- a/app/src/organisms/DropTipWizard/index.tsx +++ b/app/src/organisms/DropTipWizard/index.tsx @@ -11,11 +11,11 @@ import { COLORS, BORDERS, StyledText, + JUSTIFY_FLEX_END, } from '@opentrons/components' import { useCreateMaintenanceCommandMutation, useDeleteMaintenanceRunMutation, - useDeckConfigurationQuery, } from '@opentrons/react-api-client' import { useNotifyCurrentMaintenanceRun } from '../../resources/maintenance_runs' @@ -43,6 +43,13 @@ import { BeforeBeginning } from './BeforeBeginning' import { ChooseLocation } from './ChooseLocation' import { JogToPosition } from './JogToPosition' import { Success } from './Success' +import { InProgressModal } from '../../molecules/InProgressModal/InProgressModal' +import { + useHandleDropTipCommandErrors, + useDropTipErrorComponents, + useWizardExitHeader, +} from './utils' +import { useNotifyDeckConfigurationQuery } from '../../resources/deck_configuration' import type { PipetteData } from '@opentrons/api-client' import type { CreateMaintenanceRunType } from '@opentrons/react-api-client' @@ -54,6 +61,8 @@ import type { } from '@opentrons/shared-data' import type { Axis, Sign, StepSize } from '../../molecules/JogControls/types' import type { Jog } from '../../molecules/JogControls' +import type { ErrorDetails } from './utils' +import type { DropTipWizardStep } from './types' const RUN_REFETCH_INTERVAL_MS = 5000 const JOG_COMMAND_TIMEOUT_MS = 10000 @@ -73,7 +82,7 @@ export function DropTipWizard(props: MaintenanceRunManagerProps): JSX.Element { } = useChainMaintenanceCommands() const { createMaintenanceCommand } = useCreateMaintenanceCommandMutation() - const deckConfig = useDeckConfigurationQuery().data ?? [] + const deckConfig = useNotifyDeckConfigurationQuery().data ?? [] const [createdMaintenanceRunId, setCreatedMaintenanceRunId] = React.useState< string | null @@ -110,7 +119,7 @@ export function DropTipWizard(props: MaintenanceRunManagerProps): JSX.Element { }) .catch(e => e) }, - onError: error => setErrorMessage(error.message), + onError: error => setErrorDetails({ message: error.message }), }) const { data: maintenanceRunData } = useNotifyCurrentMaintenanceRun({ @@ -141,14 +150,16 @@ export function DropTipWizard(props: MaintenanceRunManagerProps): JSX.Element { ]) const [isExiting, setIsExiting] = React.useState(false) - const [errorMessage, setErrorMessage] = React.useState(null) + const [errorDetails, setErrorDetails] = React.useState( + null + ) const { deleteMaintenanceRun } = useDeleteMaintenanceRunMutation({ onSuccess: () => closeFlow(), onError: () => closeFlow(), }) - const handleCleanUpAndClose = (): void => { + const handleCleanUpAndClose = (homeOnExit: boolean = true): void => { if (hasCleanedUpAndClosed.current) return hasCleanedUpAndClosed.current = true @@ -156,23 +167,23 @@ export function DropTipWizard(props: MaintenanceRunManagerProps): JSX.Element { if (maintenanceRunData?.data.id == null) { closeFlow() } else { - chainRunCommands( - maintenanceRunData?.data.id, - [ - { - commandType: 'home' as const, - params: { axes: ['leftZ', 'rightZ', 'x', 'y'] }, - }, - ], - true + ;(homeOnExit + ? chainRunCommands( + maintenanceRunData?.data.id, + [ + { + commandType: 'home' as const, + params: { axes: ['leftZ', 'rightZ', 'x', 'y'] }, + }, + ], + true + ) + : new Promise((resolve, reject) => resolve()) ) - .then(() => { - deleteMaintenanceRun(maintenanceRunData?.data.id) - }) .catch(error => { console.error(error.message) - deleteMaintenanceRun(maintenanceRunData?.data.id) }) + .finally(() => deleteMaintenanceRun(maintenanceRunData?.data.id)) } } @@ -188,8 +199,8 @@ export function DropTipWizard(props: MaintenanceRunManagerProps): JSX.Element { handleCleanUpAndClose={handleCleanUpAndClose} chainRunCommands={chainRunCommands} createRunCommand={createMaintenanceCommand} - errorMessage={errorMessage} - setErrorMessage={setErrorMessage} + errorDetails={errorDetails} + setErrorDetails={setErrorDetails} isExiting={isExiting} deckConfig={deckConfig} /> @@ -203,9 +214,9 @@ interface DropTipWizardProps { createMaintenanceRun: CreateMaintenanceRunType isRobotMoving: boolean isExiting: boolean - setErrorMessage: (message: string | null) => void - errorMessage: string | null - handleCleanUpAndClose: () => void + setErrorDetails: (errorDetails: ErrorDetails) => void + errorDetails: ErrorDetails | null + handleCleanUpAndClose: (homeOnError?: boolean) => void chainRunCommands: ReturnType< typeof useChainMaintenanceCommands >['chainRunCommands'] @@ -227,20 +238,23 @@ export const DropTipWizardComponent = ( chainRunCommands, isRobotMoving, createRunCommand, - setErrorMessage, - errorMessage, + setErrorDetails, + errorDetails, isExiting, createdMaintenanceRunId, instrumentModelSpecs, deckConfig, } = props - const isOnDevice = useSelector(getIsOnDevice) const { t, i18n } = useTranslation('drop_tip_wizard') - const [currentStepIndex, setCurrentStepIndex] = React.useState(0) const [shouldDispenseLiquid, setShouldDispenseLiquid] = React.useState< boolean | null >(null) + const hasInitiatedExit = React.useRef(false) + + const isOnDevice = useSelector(getIsOnDevice) + const setSpecificErrorDetails = useHandleDropTipCommandErrors(setErrorDetails) + const DropTipWizardSteps = getDropTipWizardSteps(shouldDispenseLiquid) const currentStep = shouldDispenseLiquid != null @@ -248,11 +262,31 @@ export const DropTipWizardComponent = ( : null const isFinalStep = currentStepIndex === DropTipWizardSteps.length - 1 + const { + confirm: confirmExit, + showConfirmation: showConfirmExit, + cancel: cancelExit, + } = useConditionalConfirm(handleCleanUpAndClose, true) + + const { + button: errorExitBtn, + subHeader: errorSubHeader, + } = useDropTipErrorComponents({ + t, + errorDetails, + isOnDevice, + chainRunCommands, + maintenanceRunId: createdMaintenanceRunId, + onClose: handleCleanUpAndClose, + }) + React.useEffect(() => { if (createdMaintenanceRunId == null) { - createMaintenanceRun({}).catch((e: Error) => - setErrorMessage(`Error creating maintenance run: ${e.message}`) - ) + createMaintenanceRun({}).catch((e: Error) => { + setSpecificErrorDetails({ + message: `Error creating maintenance run: ${e.message}`, + }) + }) } }, []) @@ -280,18 +314,14 @@ export const DropTipWizardComponent = ( }, waitUntilComplete: true, timeout: JOG_COMMAND_TIMEOUT_MS, - }).catch((e: Error) => - setErrorMessage(`Error issuing jog command: ${e.message}`) - ) + }).catch((e: Error) => { + setSpecificErrorDetails({ + message: `Error issuing jog command: ${e.message}`, + }) + }) } } - const { - confirm: confirmExit, - showConfirmation: showConfirmExit, - cancel: cancelExit, - } = useConditionalConfirm(handleCleanUpAndClose, true) - const moveToAddressableArea = ( addressableArea: AddressableAreaName ): Promise => { @@ -326,189 +356,228 @@ export const DropTipWizardComponent = ( ).then(commandData => { const error = commandData[0].data.error if (error != null) { - setErrorMessage(`error moving to position: ${error.detail}`) + setSpecificErrorDetails({ + runCommandError: error, + message: `Error moving to position: ${error.detail}`, + }) } return null }) } else { - setErrorMessage(`error moving to position: invalid addressable area.`) + setSpecificErrorDetails({ + message: `Error moving to position: invalid addressable area.`, + }) return Promise.resolve(null) } } - let modalContent: JSX.Element =
UNASSIGNED STEP
- if (showConfirmExit) { - modalContent = ( - { - hasInitiatedExit.current = true - confirmExit() - }} - isRobotMoving={isRobotMoving} - /> - ) - } else if (errorMessage != null) { - modalContent = ( - - {t('drop_tip_failed')} - {errorMessage} - - } - /> - ) - } else if (shouldDispenseLiquid == null) { - modalContent = ( - - ) - } else if ( - currentStep === CHOOSE_BLOWOUT_LOCATION || - currentStep === CHOOSE_DROP_TIP_LOCATION - ) { - let bodyTextKey - if (currentStep === CHOOSE_BLOWOUT_LOCATION) { - bodyTextKey = isOnDevice - ? 'select_blowout_slot_odd' - : 'select_blowout_slot' + const modalContent = buildModalContent() + + function buildModalContent(): JSX.Element { + if (isRobotMoving) { + return buildRobotInMotion() + } else if (showConfirmExit) { + return buildShowExitConfirmation() + } else if (errorDetails != null) { + return buildErrorScreen() + } else if (shouldDispenseLiquid == null) { + return buildBeforeBeginning() + } else if ( + currentStep === CHOOSE_BLOWOUT_LOCATION || + currentStep === CHOOSE_DROP_TIP_LOCATION + ) { + return buildChooseLocation() + } else if ( + currentStep === POSITION_AND_BLOWOUT || + currentStep === POSITION_AND_DROP_TIP + ) { + return buildJogToPosition() + } else if ( + currentStep === BLOWOUT_SUCCESS || + currentStep === DROP_TIP_SUCCESS + ) { + return buildSuccess() } else { - bodyTextKey = isOnDevice - ? 'select_drop_tip_slot_odd' - : 'select_drop_tip_slot' + return
UNASSIGNED STEP
} - modalContent = ( - { - setCurrentStepIndex(0) - setShouldDispenseLiquid(null) - }} - title={ - currentStep === CHOOSE_BLOWOUT_LOCATION - ? i18n.format(t('choose_blowout_location'), 'capitalize') - : i18n.format(t('choose_drop_tip_location'), 'capitalize') - } - body={ - }} - /> - } - moveToAddressableArea={moveToAddressableArea} - isRobotMoving={isRobotMoving} - isOnDevice={isOnDevice} - setErrorMessage={setErrorMessage} - /> - ) - } else if ( - currentStep === POSITION_AND_BLOWOUT || - currentStep === POSITION_AND_DROP_TIP - ) { - modalContent = ( - { - if (createdMaintenanceRunId != null) { - chainRunCommands( - createdMaintenanceRunId, - [ - currentStep === POSITION_AND_BLOWOUT - ? { - commandType: 'blowOutInPlace', - params: { - pipetteId: MANAGED_PIPETTE_ID, - flowRate: - instrumentModelSpecs.defaultBlowOutFlowRate.value, + + function buildRobotInMotion(): JSX.Element { + return + } + + function buildShowExitConfirmation(): JSX.Element { + return ( + { + hasInitiatedExit.current = true + confirmExit() + }} + /> + ) + } + + function buildErrorScreen(): JSX.Element { + return ( + + {errorExitBtn} + + ) + } + + function buildBeforeBeginning(): JSX.Element { + return ( + + ) + } + + function buildChooseLocation(): JSX.Element { + let bodyTextKey: string + if (currentStep === CHOOSE_BLOWOUT_LOCATION) { + bodyTextKey = isOnDevice + ? 'select_blowout_slot_odd' + : 'select_blowout_slot' + } else { + bodyTextKey = isOnDevice + ? 'select_drop_tip_slot_odd' + : 'select_drop_tip_slot' + } + return ( + { + setCurrentStepIndex(0) + setShouldDispenseLiquid(null) + }} + title={ + currentStep === CHOOSE_BLOWOUT_LOCATION + ? i18n.format(t('choose_blowout_location'), 'capitalize') + : i18n.format(t('choose_drop_tip_location'), 'capitalize') + } + body={ + }} + /> + } + moveToAddressableArea={moveToAddressableArea} + isOnDevice={isOnDevice} + setErrorDetails={setSpecificErrorDetails} + /> + ) + } + + function buildJogToPosition(): JSX.Element { + return ( + { + if (createdMaintenanceRunId != null) { + chainRunCommands( + createdMaintenanceRunId, + [ + currentStep === POSITION_AND_BLOWOUT + ? { + commandType: 'blowOutInPlace', + params: { + pipetteId: MANAGED_PIPETTE_ID, + flowRate: + instrumentModelSpecs.defaultBlowOutFlowRate.value, + }, + } + : { + commandType: 'dropTipInPlace', + params: { pipetteId: MANAGED_PIPETTE_ID }, }, - } - : { - commandType: 'dropTipInPlace', - params: { pipetteId: MANAGED_PIPETTE_ID }, - }, - ], - true - ) - .then(commandData => { - const error = commandData[0].data.error - if (error != null) { - setErrorMessage(`error moving to position: ${error.detail}`) - } else proceed() - }) - .catch(e => - setErrorMessage( - `Error issuing ${ - currentStep === POSITION_AND_BLOWOUT - ? 'blowout' - : 'drop tip' - } command: ${e.message}` - ) + ], + true ) + .then(commandData => { + const error = commandData[0].data.error + if (error != null) { + setSpecificErrorDetails({ + runCommandError: error, + message: `Error moving to position: ${error.detail}`, + }) + } else { + proceed() + } + }) + .catch(e => + setSpecificErrorDetails({ + message: `Error issuing ${ + currentStep === POSITION_AND_BLOWOUT + ? 'blowout' + : 'drop tip' + } command: ${e.message}`, + }) + ) + } + }} + handleGoBack={goBack} + body={ + currentStep === POSITION_AND_BLOWOUT + ? t('position_and_blowout') + : t('position_and_drop_tip') } - }} - isRobotMoving={isRobotMoving} - handleGoBack={goBack} - body={ - currentStep === POSITION_AND_BLOWOUT - ? t('position_and_blowout') - : t('position_and_drop_tip') - } - currentStep={currentStep} - isOnDevice={isOnDevice} - /> - ) - } else if ( - currentStep === BLOWOUT_SUCCESS || - currentStep === DROP_TIP_SUCCESS - ) { - modalContent = ( - - ) + currentStep={currentStep as DropTipWizardStep} + isOnDevice={isOnDevice} + /> + ) + } + + function buildSuccess(): JSX.Element { + return ( + + ) + } } - const hasInitiatedExit = React.useRef(false) - let handleExit: () => void = () => null - if (!hasInitiatedExit.current) handleExit = confirmExit - else if (errorMessage != null) handleExit = handleCleanUpAndClose + const wizardHeaderOnExit = useWizardExitHeader({ + isFinalStep, + hasInitiatedExit: hasInitiatedExit.current, + errorDetails, + confirmExit, + handleCleanUpAndClose, + }) const wizardHeader = ( ) diff --git a/app/src/organisms/DropTipWizard/utils.tsx b/app/src/organisms/DropTipWizard/utils.tsx new file mode 100644 index 00000000000..d0a38fc768b --- /dev/null +++ b/app/src/organisms/DropTipWizard/utils.tsx @@ -0,0 +1,185 @@ +import * as React from 'react' +import { useTranslation } from 'react-i18next' + +import { AlertPrimaryButton, SPACING } from '@opentrons/components' + +import { DROP_TIP_SPECIAL_ERROR_TYPES } from './constants' +import { SmallButton } from '../../atoms/buttons' + +import type { RunCommandError } from '@opentrons/api-client' +import type { useChainMaintenanceCommands } from '../../resources/runs' + +export interface ErrorDetails { + message: string + header?: string + type?: string +} + +interface HandleDropTipCommandErrorsCbProps { + runCommandError?: RunCommandError + message?: string + header?: string + type?: RunCommandError['errorType'] +} + +/** + * @description Wraps the error state setter, updating the setter if the error should be special-cased. + */ +export function useHandleDropTipCommandErrors( + setErrorDetails: (errorDetails: ErrorDetails) => void +): (cbProps: HandleDropTipCommandErrorsCbProps) => void { + const { t } = useTranslation('drop_tip_wizard') + + return ({ + runCommandError, + message, + header, + type, + }: HandleDropTipCommandErrorsCbProps) => { + if ( + runCommandError?.errorType === + DROP_TIP_SPECIAL_ERROR_TYPES.MUST_HOME_ERROR + ) { + const headerText = t('cant_safely_drop_tips') + const messageText = t('remove_the_tips_manually') + + setErrorDetails({ + header: headerText, + message: messageText, + type: DROP_TIP_SPECIAL_ERROR_TYPES.MUST_HOME_ERROR, + }) + } else { + const messageText = message ?? '' + setErrorDetails({ header, message: messageText, type }) + } + } +} + +interface DropTipErrorComponents { + button: JSX.Element | null + subHeader: JSX.Element +} + +export interface UseDropTipErrorComponentsProps { + isOnDevice: boolean + t: (translationString: string) => string + maintenanceRunId: string | null + onClose: () => void + errorDetails: ErrorDetails | null + chainRunCommands: ReturnType< + typeof useChainMaintenanceCommands + >['chainRunCommands'] +} + +/** + * @description Returns special-cased components given error details. + */ +export function useDropTipErrorComponents({ + t, + maintenanceRunId, + onClose, + errorDetails, + isOnDevice, + chainRunCommands, +}: UseDropTipErrorComponentsProps): DropTipErrorComponents { + return errorDetails?.type === DROP_TIP_SPECIAL_ERROR_TYPES.MUST_HOME_ERROR + ? buildHandleMustHome() + : buildGenericError() + + function buildGenericError(): DropTipErrorComponents { + return { + button: null, + subHeader: ( + <> + {t('drop_tip_failed')} +
+ {errorDetails?.message} + + ), + } + } + + function buildHandleMustHome(): DropTipErrorComponents { + const handleOnClick = (): void => { + if (maintenanceRunId !== null) { + void chainRunCommands( + maintenanceRunId, + [ + { + commandType: 'home' as const, + params: {}, + }, + ], + true + ) + onClose() + } + } + + return { + button: isOnDevice ? ( + + ) : ( + + {t('confirm_removal_and_home')} + + ), + subHeader: <>{errorDetails?.message}, + } + } +} + +export interface UseWizardExitHeaderProps { + isFinalStep: boolean + hasInitiatedExit: boolean + errorDetails: ErrorDetails | null + handleCleanUpAndClose: (homeOnError?: boolean) => void + confirmExit: (homeOnError?: boolean) => void +} + +/** + * @description Determines the appropriate onClick for the wizard exit button, ensuring the exit logic can occur at + * most one time. + */ +export function useWizardExitHeader({ + isFinalStep, + hasInitiatedExit, + errorDetails, + handleCleanUpAndClose, + confirmExit, +}: UseWizardExitHeaderProps): () => void { + return buildHandleExit() + + function buildHandleExit(): () => void { + if (!hasInitiatedExit) { + if (errorDetails != null) { + // When an error occurs, do not home when exiting the flow via the wizard header. + return buildNoHomeCleanUpAndClose() + } else if (isFinalStep) { + return buildHandleCleanUpAndClose() + } else { + return buildConfirmExit() + } + } else { + return buildGenericCase() + } + } + + function buildGenericCase(): () => void { + return () => null + } + function buildNoHomeCleanUpAndClose(): () => void { + return () => handleCleanUpAndClose(false) + } + function buildHandleCleanUpAndClose(): () => void { + return handleCleanUpAndClose + } + function buildConfirmExit(): () => void { + return confirmExit + } +} diff --git a/app/src/organisms/EmergencyStop/EstopPressedModal.tsx b/app/src/organisms/EmergencyStop/EstopPressedModal.tsx index cb32ae550b9..3cd06ff2fd8 100644 --- a/app/src/organisms/EmergencyStop/EstopPressedModal.tsx +++ b/app/src/organisms/EmergencyStop/EstopPressedModal.tsx @@ -73,7 +73,7 @@ function TouchscreenModal({ isEngaged, closeModal, }: EstopPressedModalProps): JSX.Element { - const { t } = useTranslation('device_settings') + const { t } = useTranslation(['device_settings', 'branded']) const [isResuming, setIsResuming] = React.useState(false) const { acknowledgeEstopDisengage } = useAcknowledgeEstopDisengageMutation() const modalHeader: ModalHeaderBaseProps = { @@ -94,7 +94,7 @@ function TouchscreenModal({ - {t('estop_pressed_description')} + {t('branded:estop_pressed_description')} - {t('estop_pressed_description')} + {t('branded:estop_pressed_description')} + + + {t('before_you_begin')} + + }} + /> + + + + ) + } else { + return null + } +} diff --git a/app/src/organisms/ErrorRecoveryFlows/ErrorRecoveryHeader.tsx b/app/src/organisms/ErrorRecoveryFlows/ErrorRecoveryHeader.tsx new file mode 100644 index 00000000000..0c501149b82 --- /dev/null +++ b/app/src/organisms/ErrorRecoveryFlows/ErrorRecoveryHeader.tsx @@ -0,0 +1,90 @@ +import * as React from 'react' +import { useTranslation } from 'react-i18next' +import { css } from 'styled-components' + +import { + Box, + DIRECTION_ROW, + BORDERS, + ALIGN_CENTER, + Flex, + JUSTIFY_SPACE_BETWEEN, + TYPOGRAPHY, + COLORS, + SPACING, + RESPONSIVENESS, + StyledText, + Icon, +} from '@opentrons/components' + +import { useErrorName } from './utils' +import { NON_DESIGN_SANCTIONED_COLOR_1 } from './constants' + +import type { ErrorKind } from './types' + +interface ErrorRecoveryHeaderProps { + errorKind: ErrorKind +} +export function ErrorRecoveryHeader({ + errorKind, +}: ErrorRecoveryHeaderProps): JSX.Element { + const { t } = useTranslation('error_recovery') + const errorName = useErrorName(errorKind) + + return ( + + + + {t('recovery_mode')} + + + {errorName} + + + + + ) +} + +function AlertHeaderIcon(): JSX.Element { + return ( + + ) +} + +const BOX_STYLE = css` + background-color: ${NON_DESIGN_SANCTIONED_COLOR_1}; + @media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} { + border-radius: ${BORDERS.borderRadius12} ${BORDERS.borderRadius12} 0 0; + } +` +const HEADER_CONTAINER_STYLE = css` + flex-direction: ${DIRECTION_ROW}; + justify-content: ${JUSTIFY_SPACE_BETWEEN}; + padding: ${SPACING.spacing16} ${SPACING.spacing32}; + @media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} { + padding: 1.75rem ${SPACING.spacing32}; + } +` +const HEADER_TEXT_STYLE = css` + ${TYPOGRAPHY.pSemiBold} + color: ${COLORS.white}; + cursor: default; + + @media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} { + font-size: ${TYPOGRAPHY.fontSize22}; + font-weight: ${TYPOGRAPHY.fontWeightBold}; + line-height: ${TYPOGRAPHY.lineHeight28}; + } +` diff --git a/app/src/organisms/ErrorRecoveryFlows/RecoveryInProgress.tsx b/app/src/organisms/ErrorRecoveryFlows/RecoveryInProgress.tsx new file mode 100644 index 00000000000..a30d8dd2f0a --- /dev/null +++ b/app/src/organisms/ErrorRecoveryFlows/RecoveryInProgress.tsx @@ -0,0 +1,30 @@ +import * as React from 'react' +import { useTranslation } from 'react-i18next' + +import { InProgressModal } from '../../molecules/InProgressModal/InProgressModal' +import { RECOVERY_MAP } from './constants' + +import type { RobotMovingRoute, RecoveryContentProps } from './types' + +export function RecoveryInProgress({ + recoveryMap, +}: RecoveryContentProps): JSX.Element { + const { ROBOT_IN_MOTION, ROBOT_RESUMING } = RECOVERY_MAP + const { t } = useTranslation('error_recovery') + const { route } = recoveryMap + + const buildDescription = (): RobotMovingRoute => { + switch (route) { + case ROBOT_IN_MOTION.ROUTE: + return t('stand_back') + case ROBOT_RESUMING.ROUTE: + return t('stand_back_resuming') + default: + return t('stand_back') + } + } + + const description = buildDescription() + + return +} diff --git a/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/ResumeRun.tsx b/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/ResumeRun.tsx new file mode 100644 index 00000000000..982e1a01129 --- /dev/null +++ b/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/ResumeRun.tsx @@ -0,0 +1,62 @@ +import * as React from 'react' +import { useTranslation } from 'react-i18next' + +import { + ALIGN_CENTER, + DIRECTION_COLUMN, + Flex, + Icon, + JUSTIFY_SPACE_BETWEEN, + SPACING, + StyledText, +} from '@opentrons/components' + +import { RecoveryFooterButtons } from './shared' + +import type { RecoveryContentProps } from '../types' + +export function ResumeRun({ + isOnDevice, + onComplete, + routeUpdateActions, +}: RecoveryContentProps): JSX.Element | null { + const { t } = useTranslation('error_recovery') + const { goBackPrevStep } = routeUpdateActions + + if (isOnDevice) { + return ( + + + + + {t('are_you_sure_you_want_to_resume')} + + + {t('run_will_resume')} + + + + + ) + } else { + return null + } +} diff --git a/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/SelectRecoveryOption.tsx b/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/SelectRecoveryOption.tsx new file mode 100644 index 00000000000..7399118ad80 --- /dev/null +++ b/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/SelectRecoveryOption.tsx @@ -0,0 +1,118 @@ +import * as React from 'react' +import head from 'lodash/head' +import { useTranslation } from 'react-i18next' + +import { + DIRECTION_COLUMN, + Flex, + JUSTIFY_SPACE_BETWEEN, + SPACING, + StyledText, +} from '@opentrons/components' + +import { + RECOVERY_MAP, + ERROR_KINDS, + ODD_SECTION_TITLE_STYLE, +} from '../constants' +import { RadioButton } from '../../../atoms/buttons' +import { RecoveryFooterButtons } from './shared' + +import type { ErrorKind, RecoveryContentProps, RecoveryRoute } from '../types' + +// The "home" screen within Error Recovery. When a user completes a non-terminal flow or presses "Go back" enough +// to escape the boundaries of a route, they will be redirected here. +export function SelectRecoveryOption({ + isOnDevice, + errorKind, + routeUpdateActions, +}: RecoveryContentProps): JSX.Element | null { + const { t } = useTranslation('error_recovery') + const { proceedToRoute } = routeUpdateActions + const validRecoveryOptions = getRecoveryOptions(errorKind) + const [selectedRoute, setSelectedRoute] = React.useState( + head(validRecoveryOptions) as RecoveryRoute + ) + + if (isOnDevice) { + return ( + + + {t('how_do_you_want_to_proceed')} + + + + + + proceedToRoute(selectedRoute as RecoveryRoute) + } + secondaryBtnOnClick={() => + proceedToRoute(RECOVERY_MAP.BEFORE_BEGINNING.ROUTE) + } + /> + + ) + } else { + return null + } +} + +interface RecoveryOptionsProps { + validRecoveryOptions: RecoveryRoute[] + setSelectedRoute: (route: RecoveryRoute) => void + selectedRoute?: RecoveryRoute +} +export function RecoveryOptions({ + validRecoveryOptions, + selectedRoute, + setSelectedRoute, +}: RecoveryOptionsProps): JSX.Element[] { + const { t } = useTranslation('error_recovery') + + return validRecoveryOptions.map((recoveryOption: RecoveryRoute) => { + const buildOptionName = (): string => { + switch (recoveryOption) { + case RECOVERY_MAP.RESUME.ROUTE: + return t('resume') + case RECOVERY_MAP.CANCEL_RUN.ROUTE: + return t('cancel_run') + default: + return 'INVALID_OPTION' + } + } + const optionName = buildOptionName() + + return ( + setSelectedRoute(recoveryOption)} + isSelected={recoveryOption === selectedRoute} + /> + ) + }) +} + +export function getRecoveryOptions(errorKind: ErrorKind): RecoveryRoute[] { + switch (errorKind) { + case ERROR_KINDS.GENERAL_ERROR: + return GENERAL_ERROR_OPTIONS + } +} + +export const GENERAL_ERROR_OPTIONS: RecoveryRoute[] = [ + RECOVERY_MAP.RESUME.ROUTE, + RECOVERY_MAP.CANCEL_RUN.ROUTE, +] diff --git a/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/__tests__/ResumeRun.test.tsx b/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/__tests__/ResumeRun.test.tsx new file mode 100644 index 00000000000..ca7d83e297d --- /dev/null +++ b/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/__tests__/ResumeRun.test.tsx @@ -0,0 +1,58 @@ +import * as React from 'react' +import { vi, describe, it, expect, beforeEach } from 'vitest' +import { screen, fireEvent } from '@testing-library/react' + +import { renderWithProviders } from '../../../../__testing-utils__' +import { i18n } from '../../../../i18n' +import { ResumeRun } from '../ResumeRun' +import { RECOVERY_MAP, ERROR_KINDS } from '../../constants' + +import type { Mock } from 'vitest' + +const render = (props: React.ComponentProps) => { + return renderWithProviders(, { + i18nInstance: i18n, + })[0] +} + +describe('RecoveryFooterButtons', () => { + const { RESUME } = RECOVERY_MAP + let props: React.ComponentProps + let mockOnComplete: Mock + let mockGoBackPrevStep: Mock + + beforeEach(() => { + mockOnComplete = vi.fn() + mockGoBackPrevStep = vi.fn() + const mockRouteUpdateActions = { goBackPrevStep: mockGoBackPrevStep } as any + + props = { + isOnDevice: true, + errorKind: ERROR_KINDS.GENERAL_ERROR, + onComplete: mockOnComplete, + routeUpdateActions: mockRouteUpdateActions, + recoveryMap: { + route: RESUME.ROUTE, + step: RESUME.STEPS.CONFIRM_RESUME, + }, + } + }) + + it('renders appropriate copy and click behavior', () => { + render(props) + + screen.getByText('Are you sure you want to resume?') + screen.queryByText( + 'The run will resume from the point at which the error occurred.' + ) + + const primaryBtn = screen.getByRole('button', { name: 'Confirm' }) + const secondaryBtn = screen.getByRole('button', { name: 'Go back' }) + + fireEvent.click(primaryBtn) + fireEvent.click(secondaryBtn) + + expect(mockOnComplete).toHaveBeenCalled() + expect(mockGoBackPrevStep).toHaveBeenCalled() + }) +}) diff --git a/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/__tests__/SelectRecoveryOptions.test.tsx b/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/__tests__/SelectRecoveryOptions.test.tsx new file mode 100644 index 00000000000..81e47d85dac --- /dev/null +++ b/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/__tests__/SelectRecoveryOptions.test.tsx @@ -0,0 +1,115 @@ +import * as React from 'react' +import { vi, describe, it, expect, beforeEach } from 'vitest' +import { screen, fireEvent } from '@testing-library/react' + +import { renderWithProviders } from '../../../../__testing-utils__' +import { i18n } from '../../../../i18n' +import { + SelectRecoveryOption, + RecoveryOptions, + getRecoveryOptions, + GENERAL_ERROR_OPTIONS, +} from '../SelectRecoveryOption' +import { RECOVERY_MAP, ERROR_KINDS } from '../../constants' + +import type { Mock } from 'vitest' + +const renderSelectRecoveryOption = ( + props: React.ComponentProps +) => { + return renderWithProviders(, { + i18nInstance: i18n, + })[0] +} + +const renderRecoveryOptions = ( + props: React.ComponentProps +) => { + return renderWithProviders(, { + i18nInstance: i18n, + })[0] +} + +describe('SelectRecoveryOption', () => { + const { RESUME } = RECOVERY_MAP + let props: React.ComponentProps + let mockProceedToRoute: Mock + + beforeEach(() => { + mockProceedToRoute = vi.fn() + const mockRouteUpdateActions = { proceedToRoute: mockProceedToRoute } as any + + props = { + isOnDevice: true, + errorKind: ERROR_KINDS.GENERAL_ERROR, + onComplete: vi.fn(), + routeUpdateActions: mockRouteUpdateActions, + recoveryMap: { + route: RESUME.ROUTE, + step: RESUME.STEPS.CONFIRM_RESUME, + }, + } + }) + + it('renders appropriate general copy and click behavior', () => { + renderSelectRecoveryOption(props) + + screen.getByText('How do you want to proceed?') + + const resumeOptionRadioLabel = screen.getByRole('label', { name: 'Resume' }) + const primaryBtn = screen.getByRole('button', { name: 'Continue' }) + const secondaryBtn = screen.getByRole('button', { name: 'Go back' }) + + fireEvent.click(resumeOptionRadioLabel) + fireEvent.click(primaryBtn) + + expect(mockProceedToRoute).toHaveBeenCalledWith(RESUME.ROUTE) + + renderSelectRecoveryOption(props) + + fireEvent.click(secondaryBtn) + + expect(mockProceedToRoute).toHaveBeenCalledWith( + RECOVERY_MAP.BEFORE_BEGINNING.ROUTE + ) + }) +}) + +describe('RecoveryOptions', () => { + let props: React.ComponentProps + let mockSetSelectedRoute: Mock + + beforeEach(() => { + mockSetSelectedRoute = vi.fn() + const generalRecoveryOptions = getRecoveryOptions(ERROR_KINDS.GENERAL_ERROR) + + props = { + validRecoveryOptions: generalRecoveryOptions, + setSelectedRoute: mockSetSelectedRoute, + } + }) + + it('renders valid recovery options for a general error errorKind', () => { + renderRecoveryOptions(props) + + screen.getByRole('label', { name: 'Resume' }) + screen.getByRole('label', { name: 'Cancel run' }) + }) + + it('updates the selectedRoute when a new option is selected', () => { + renderRecoveryOptions(props) + + fireEvent.click(screen.getByRole('label', { name: 'Cancel run' })) + + expect(mockSetSelectedRoute).toHaveBeenCalledWith( + RECOVERY_MAP.CANCEL_RUN.ROUTE + ) + }) +}) + +describe('getRecoveryOptions', () => { + it(`returns general error options when the errorKind is ${ERROR_KINDS.GENERAL_ERROR}`, () => { + const generalErrorOptions = getRecoveryOptions(ERROR_KINDS.GENERAL_ERROR) + expect(generalErrorOptions).toBe(GENERAL_ERROR_OPTIONS) + }) +}) diff --git a/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/index.ts b/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/index.ts new file mode 100644 index 00000000000..c39d9e883c6 --- /dev/null +++ b/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/index.ts @@ -0,0 +1,2 @@ +export { SelectRecoveryOption } from './SelectRecoveryOption' +export { ResumeRun } from './ResumeRun' diff --git a/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/shared/RecoveryFooterButtons.tsx b/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/shared/RecoveryFooterButtons.tsx new file mode 100644 index 00000000000..64264630c2d --- /dev/null +++ b/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/shared/RecoveryFooterButtons.tsx @@ -0,0 +1,64 @@ +import * as React from 'react' +import { useTranslation } from 'react-i18next' + +import { + ALIGN_CENTER, + Flex, + JUSTIFY_CENTER, + JUSTIFY_SPACE_BETWEEN, + SPACING, +} from '@opentrons/components' + +import { SmallButton } from '../../../../atoms/buttons' +import { + NON_SANCTIONED_RECOVERY_COLOR_STYLE_PRIMARY, + NON_SANCTIONED_RECOVERY_COLOR_STYLE_SECONDARY, +} from '../../constants' + +interface RecoveryOptionProps { + isOnDevice: boolean + secondaryBtnOnClick: () => void + primaryBtnOnClick: () => void + primaryBtnTextOverride?: string +} +export function RecoveryFooterButtons({ + isOnDevice, + secondaryBtnOnClick, + primaryBtnOnClick, + primaryBtnTextOverride, +}: RecoveryOptionProps): JSX.Element | null { + const { t } = useTranslation('error_recovery') + + if (isOnDevice) { + return ( + + + + + ) + } else { + return null + } +} diff --git a/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/shared/__tests__/RecoveryFooterButtons.test.tsx b/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/shared/__tests__/RecoveryFooterButtons.test.tsx new file mode 100644 index 00000000000..6933177e22c --- /dev/null +++ b/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/shared/__tests__/RecoveryFooterButtons.test.tsx @@ -0,0 +1,51 @@ +import * as React from 'react' +import { vi, describe, it, expect, beforeEach } from 'vitest' +import { screen, fireEvent } from '@testing-library/react' + +import { renderWithProviders } from '../../../../../__testing-utils__' +import { i18n } from '../../../../../i18n' +import { RecoveryFooterButtons } from '../RecoveryFooterButtons' + +import type { Mock } from 'vitest' + +const render = (props: React.ComponentProps) => { + return renderWithProviders(, { + i18nInstance: i18n, + })[0] +} + +describe('RecoveryFooterButtons', () => { + let props: React.ComponentProps + let mockPrimaryBtnOnClick: Mock + let mockSecondaryBtnOnClick: Mock + + beforeEach(() => { + mockPrimaryBtnOnClick = vi.fn() + mockSecondaryBtnOnClick = vi.fn() + props = { + isOnDevice: true, + primaryBtnOnClick: mockPrimaryBtnOnClick, + secondaryBtnOnClick: mockSecondaryBtnOnClick, + } + }) + + it('renders default button copy and click behavior', () => { + render(props) + + const primaryBtn = screen.getByRole('button', { name: 'Continue' }) + const secondaryBtn = screen.getByRole('button', { name: 'Go back' }) + + fireEvent.click(primaryBtn) + fireEvent.click(secondaryBtn) + + expect(mockPrimaryBtnOnClick).toHaveBeenCalled() + expect(mockSecondaryBtnOnClick).toHaveBeenCalled() + }) + + it('renders alternative button text when supplied', () => { + props = { ...props, primaryBtnTextOverride: 'MOCK_OVERRIDE_TEXT' } + render(props) + + screen.getByRole('button', { name: 'MOCK_OVERRIDE_TEXT' }) + }) +}) diff --git a/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/shared/index.ts b/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/shared/index.ts new file mode 100644 index 00000000000..82d6cdb7120 --- /dev/null +++ b/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/shared/index.ts @@ -0,0 +1 @@ +export { RecoveryFooterButtons } from './RecoveryFooterButtons' diff --git a/app/src/organisms/ErrorRecoveryFlows/__tests__/BeforeBeginning.test.tsx b/app/src/organisms/ErrorRecoveryFlows/__tests__/BeforeBeginning.test.tsx new file mode 100644 index 00000000000..d9e8ed280c5 --- /dev/null +++ b/app/src/organisms/ErrorRecoveryFlows/__tests__/BeforeBeginning.test.tsx @@ -0,0 +1,57 @@ +import * as React from 'react' +import { beforeEach, describe, expect, it, vi } from 'vitest' +import { fireEvent, screen } from '@testing-library/react' + +import { renderWithProviders } from '../../../__testing-utils__' +import { i18n } from '../../../i18n' +import { BeforeBeginning } from '../BeforeBeginning' +import { ERROR_KINDS, RECOVERY_MAP } from '../constants' + +import type { Mock } from 'vitest' + +const render = (props: React.ComponentProps) => { + return renderWithProviders(, { + i18nInstance: i18n, + })[0] +} + +describe('BeforeBeginning', () => { + const { BEFORE_BEGINNING } = RECOVERY_MAP + let props: React.ComponentProps + let mockProceedNextStep: Mock + + beforeEach(() => { + mockProceedNextStep = vi.fn() + const mockRouteUpdateActions = { + proceedNextStep: mockProceedNextStep, + } as any + + props = { + isOnDevice: true, + errorKind: ERROR_KINDS.GENERAL_ERROR, + onComplete: vi.fn(), + routeUpdateActions: mockRouteUpdateActions, + recoveryMap: { + route: BEFORE_BEGINNING.ROUTE, + step: BEFORE_BEGINNING.STEPS.RECOVERY_DESCRIPTION, + }, + } + }) + + it('renders appropriate copy and click behavior', () => { + render(props) + + screen.getByText('Before you begin') + screen.queryByText( + 'Recovery Mode provides you with guided and manual controls for handling errors at runtime.' + ) + + const primaryBtn = screen.getByRole('button', { + name: 'View recovery options', + }) + + fireEvent.click(primaryBtn) + + expect(mockProceedNextStep).toHaveBeenCalled() + }) +}) diff --git a/app/src/organisms/ErrorRecoveryFlows/__tests__/ErrorRecoveryFlows.test.tsx b/app/src/organisms/ErrorRecoveryFlows/__tests__/ErrorRecoveryFlows.test.tsx new file mode 100644 index 00000000000..93ca813ba37 --- /dev/null +++ b/app/src/organisms/ErrorRecoveryFlows/__tests__/ErrorRecoveryFlows.test.tsx @@ -0,0 +1,114 @@ +import * as React from 'react' +import { vi, describe, it, beforeEach } from 'vitest' +import { screen } from '@testing-library/react' + +import { renderWithProviders } from '../../../__testing-utils__' +import { i18n } from '../../../i18n' +import { ErrorRecoveryContent } from '..' +import { ERROR_KINDS, RECOVERY_MAP } from '../constants' +import { BeforeBeginning } from '../BeforeBeginning' +import { SelectRecoveryOption, ResumeRun } from '../RecoveryOptions' +import { RecoveryInProgress } from '../RecoveryInProgress' + +import type { IRecoveryMap } from '../types' + +vi.mock('../BeforeBeginning') +vi.mock('../RecoveryOptions') +vi.mock('../RecoveryInProgress') + +const render = (props: React.ComponentProps) => { + return renderWithProviders(, { + i18nInstance: i18n, + })[0] +} + +describe('ErrorRecoveryContent', () => { + const { + OPTION_SELECTION, + BEFORE_BEGINNING, + RESUME, + ROBOT_RESUMING, + ROBOT_IN_MOTION, + } = RECOVERY_MAP + + let props: React.ComponentProps + const mockRecoveryMap: IRecoveryMap = { + route: OPTION_SELECTION.ROUTE, + step: OPTION_SELECTION.STEPS.SELECT, + } + + beforeEach(() => { + props = { + errorKind: ERROR_KINDS.GENERAL_ERROR, + routeUpdateActions: {} as any, + recoveryMap: mockRecoveryMap, + onComplete: vi.fn(), + isOnDevice: true, + } + + vi.mocked(SelectRecoveryOption).mockReturnValue( +
MOCK_SELECT_RECOVERY_OPTION
+ ) + vi.mocked(BeforeBeginning).mockReturnValue(
MOCK_BEFORE_BEGINNING
) + vi.mocked(ResumeRun).mockReturnValue(
MOCK_RESUME_RUN
) + vi.mocked(RecoveryInProgress).mockReturnValue(
MOCK_IN_PROGRESS
) + }) + + it(`returns SelectRecoveryOption when the route is ${OPTION_SELECTION.ROUTE}`, () => { + render(props) + + screen.getByText('MOCK_SELECT_RECOVERY_OPTION') + }) + + it(`returns BeforeBeginning when the route is ${BEFORE_BEGINNING.ROUTE}`, () => { + props = { + ...props, + recoveryMap: { + ...props.recoveryMap, + route: BEFORE_BEGINNING.ROUTE, + }, + } + render(props) + + screen.getByText('MOCK_BEFORE_BEGINNING') + }) + + it(`returns ResumeRun when the route is ${RESUME.ROUTE}`, () => { + props = { + ...props, + recoveryMap: { + ...props.recoveryMap, + route: RESUME.ROUTE, + }, + } + render(props) + + screen.getByText('MOCK_RESUME_RUN') + }) + + it(`returns RecoveryInProgressModal when the route is ${ROBOT_IN_MOTION.ROUTE}`, () => { + props = { + ...props, + recoveryMap: { + ...props.recoveryMap, + route: ROBOT_IN_MOTION.ROUTE, + }, + } + render(props) + + screen.getByText('MOCK_IN_PROGRESS') + }) + + it(`returns RecoveryInProgressModal when the route is ${ROBOT_RESUMING.ROUTE}`, () => { + props = { + ...props, + recoveryMap: { + ...props.recoveryMap, + route: ROBOT_IN_MOTION.ROUTE, + }, + } + render(props) + + screen.getByText('MOCK_IN_PROGRESS') + }) +}) diff --git a/app/src/organisms/ErrorRecoveryFlows/__tests__/ErrorRecoveryHeader.test.tsx b/app/src/organisms/ErrorRecoveryFlows/__tests__/ErrorRecoveryHeader.test.tsx new file mode 100644 index 00000000000..31e9f596728 --- /dev/null +++ b/app/src/organisms/ErrorRecoveryFlows/__tests__/ErrorRecoveryHeader.test.tsx @@ -0,0 +1,36 @@ +import * as React from 'react' +import { screen } from '@testing-library/react' +import { beforeEach, describe, it } from 'vitest' + +import { renderWithProviders } from '../../../__testing-utils__' +import { i18n } from '../../../i18n' +import { ErrorRecoveryHeader } from '../ErrorRecoveryHeader' +import { ERROR_KINDS } from '../constants' + +const render = (props: React.ComponentProps) => { + return renderWithProviders(, { + i18nInstance: i18n, + })[0] +} + +describe('ErrorRecoveryHeader', () => { + let props: React.ComponentProps + + beforeEach(() => { + props = { + errorKind: ERROR_KINDS.GENERAL_ERROR, + } + }) + + it('renders appropriate copy independent of errorKind', () => { + render(props) + + screen.getByText('Recovery Mode') + }) + + it('renders the appropriate header for a general error kind', () => { + render(props) + + screen.getByText('General error') + }) +}) diff --git a/app/src/organisms/ErrorRecoveryFlows/__tests__/RecoveryInProgress.test.tsx b/app/src/organisms/ErrorRecoveryFlows/__tests__/RecoveryInProgress.test.tsx new file mode 100644 index 00000000000..2811c2dafad --- /dev/null +++ b/app/src/organisms/ErrorRecoveryFlows/__tests__/RecoveryInProgress.test.tsx @@ -0,0 +1,51 @@ +import * as React from 'react' +import { beforeEach, describe, it, vi } from 'vitest' +import { screen } from '@testing-library/react' + +import { renderWithProviders } from '../../../__testing-utils__' +import { i18n } from '../../../i18n' +import { RecoveryInProgress } from '../RecoveryInProgress' +import { ERROR_KINDS, RECOVERY_MAP } from '../constants' + +const render = (props: React.ComponentProps) => { + return renderWithProviders(, { + i18nInstance: i18n, + })[0] +} + +describe('RecoveryInProgress', () => { + const { ROBOT_IN_MOTION, ROBOT_RESUMING } = RECOVERY_MAP + let props: React.ComponentProps + + beforeEach(() => { + props = { + isOnDevice: true, + errorKind: ERROR_KINDS.GENERAL_ERROR, + onComplete: vi.fn(), + routeUpdateActions: vi.fn() as any, + recoveryMap: { + route: ROBOT_IN_MOTION.ROUTE, + step: ROBOT_IN_MOTION.STEPS.IN_MOTION, + }, + } + }) + + it(`renders appropriate copy when the route is ${ROBOT_IN_MOTION.ROUTE}`, () => { + render(props) + + screen.getByText('Stand back, robot is in motion') + }) + + it(`renders appropriate copy when the route is ${ROBOT_RESUMING.ROUTE}`, () => { + props = { + ...props, + recoveryMap: { + route: ROBOT_RESUMING.ROUTE, + step: ROBOT_RESUMING.STEPS.RESUMING, + }, + } + render(props) + + screen.getByText('Stand back, resuming current step') + }) +}) diff --git a/app/src/organisms/ErrorRecoveryFlows/__tests__/utils.test.ts b/app/src/organisms/ErrorRecoveryFlows/__tests__/utils.test.ts new file mode 100644 index 00000000000..29da7e1a213 --- /dev/null +++ b/app/src/organisms/ErrorRecoveryFlows/__tests__/utils.test.ts @@ -0,0 +1,137 @@ +import { vi, describe, it, expect, beforeEach } from 'vitest' +import { renderHook } from '@testing-library/react' + +import { ERROR_KINDS, INVALID, RECOVERY_MAP } from '../constants' +import { + getErrorKind, + getRecoveryRouteNavigation, + useRouteUpdateActions, +} from '../utils' + +import type { Mock } from 'vitest' +import type { GetRouteUpdateActionsParams } from '../utils' + +describe('getErrorKind', () => { + it(`returns ${ERROR_KINDS.GENERAL_ERROR} if the errorType isn't handled explicitly`, () => { + const mockErrorType = 'NON_HANDLED_ERROR' + const result = getErrorKind(mockErrorType) + expect(result).toEqual(ERROR_KINDS.GENERAL_ERROR) + }) +}) + +describe('getRecoveryRouteNavigation', () => { + it(`getNextStep and getPrevStep return ${INVALID} if the recovery route does not contain multiple steps`, () => { + const { ROBOT_IN_MOTION } = RECOVERY_MAP + const { getNextStep, getPrevStep } = getRecoveryRouteNavigation( + ROBOT_IN_MOTION.ROUTE + ) + const nextStepResult = getNextStep(ROBOT_IN_MOTION.STEPS.IN_MOTION) + const prevStepResult = getPrevStep(ROBOT_IN_MOTION.STEPS.IN_MOTION) + + expect(nextStepResult).toEqual(INVALID) + expect(prevStepResult).toEqual(INVALID) + }) +}) + +describe('useRouteUpdateActions', () => { + const { OPTION_SELECTION } = RECOVERY_MAP + + let useRouteUpdateActionsParams: GetRouteUpdateActionsParams + let mockSetRecoveryMap: Mock + + beforeEach(() => { + mockSetRecoveryMap = vi.fn() + + useRouteUpdateActionsParams = { + recoveryMap: { + route: RECOVERY_MAP.RESUME.ROUTE, + step: RECOVERY_MAP.RESUME.STEPS.CONFIRM_RESUME, + }, + setRecoveryMap: mockSetRecoveryMap, + } + }) + + it(`routes to ${OPTION_SELECTION.ROUTE} ${OPTION_SELECTION.STEPS.SELECT} if proceedNextStep is called and the next step does not exist`, () => { + const { result } = renderHook(() => + useRouteUpdateActions(useRouteUpdateActionsParams) + ) + const { proceedNextStep } = result.current + + proceedNextStep() + expect(mockSetRecoveryMap).toHaveBeenCalledWith({ + route: OPTION_SELECTION.ROUTE, + step: OPTION_SELECTION.STEPS.SELECT, + }) + }) + + it(`routes to ${OPTION_SELECTION.ROUTE} ${OPTION_SELECTION.STEPS.SELECT} if proceedPrevStep is called and the previous step does not exist`, () => { + const { result } = renderHook(() => + useRouteUpdateActions(useRouteUpdateActionsParams) + ) + const { goBackPrevStep } = result.current + + goBackPrevStep() + expect(mockSetRecoveryMap).toHaveBeenCalledWith({ + route: OPTION_SELECTION.ROUTE, + step: OPTION_SELECTION.STEPS.SELECT, + }) + }) + + it('routes to the first step of the supplied route when proceedToRoute is called', () => { + const { result } = renderHook(() => + useRouteUpdateActions(useRouteUpdateActionsParams) + ) + const { proceedToRoute } = result.current + + proceedToRoute(RECOVERY_MAP.ROBOT_IN_MOTION.ROUTE) + expect(mockSetRecoveryMap).toHaveBeenCalledWith({ + route: RECOVERY_MAP.ROBOT_IN_MOTION.ROUTE, + step: RECOVERY_MAP.ROBOT_IN_MOTION.STEPS.IN_MOTION, + }) + }) + + it('routes to "robot in motion" when no other motion path is specified', () => { + const { result } = renderHook(() => + useRouteUpdateActions(useRouteUpdateActionsParams) + ) + const { setRobotInMotion } = result.current + + setRobotInMotion(true) + expect(mockSetRecoveryMap).toHaveBeenCalledWith({ + route: RECOVERY_MAP.ROBOT_IN_MOTION.ROUTE, + step: RECOVERY_MAP.ROBOT_IN_MOTION.STEPS.IN_MOTION, + }) + }) + + it('routes to alternative motion routes if specified', () => { + const { result } = renderHook(() => + useRouteUpdateActions(useRouteUpdateActionsParams) + ) + const { setRobotInMotion } = result.current + + setRobotInMotion(true, RECOVERY_MAP.ROBOT_RESUMING.ROUTE) + expect(mockSetRecoveryMap).toHaveBeenCalledWith({ + route: RECOVERY_MAP.ROBOT_RESUMING.ROUTE, + step: RECOVERY_MAP.ROBOT_RESUMING.STEPS.RESUMING, + }) + }) + + it('routes to the route prior to motion after the motion completes', () => { + const { result } = renderHook(() => + useRouteUpdateActions(useRouteUpdateActionsParams) + ) + const { setRobotInMotion } = result.current + + setRobotInMotion(true) + expect(mockSetRecoveryMap).toHaveBeenCalledWith({ + route: RECOVERY_MAP.ROBOT_IN_MOTION.ROUTE, + step: RECOVERY_MAP.ROBOT_IN_MOTION.STEPS.IN_MOTION, + }) + + setRobotInMotion(false) + expect(mockSetRecoveryMap).toHaveBeenCalledWith({ + route: RECOVERY_MAP.OPTION_SELECTION.ROUTE, + step: RECOVERY_MAP.OPTION_SELECTION.STEPS.SELECT, + }) + }) +}) diff --git a/app/src/organisms/ErrorRecoveryFlows/constants.ts b/app/src/organisms/ErrorRecoveryFlows/constants.ts new file mode 100644 index 00000000000..4a27ea62db8 --- /dev/null +++ b/app/src/organisms/ErrorRecoveryFlows/constants.ts @@ -0,0 +1,114 @@ +import { css } from 'styled-components' + +import { SPACING, TYPOGRAPHY } from '@opentrons/components' + +import type { StepOrder } from './types' + +export const ERROR_KINDS = { + GENERAL_ERROR: 'GENERAL_ERROR', +} as const + +// Valid recovery routes and steps. +export const RECOVERY_MAP = { + BEFORE_BEGINNING: { + ROUTE: 'before-beginning', + STEPS: { + RECOVERY_DESCRIPTION: 'recovery-description', + }, + }, + CANCEL_RUN: { ROUTE: 'cancel-run', STEPS: {} }, + DROP_TIP: { ROUTE: 'drop-tip', STEPS: {} }, + IGNORE_AND_RESUME: { ROUTE: 'ignore-and-resume', STEPS: {} }, + REFILL_AND_RESUME: { ROUTE: 'refill-and-resume', STEPS: {} }, + RESUME: { + ROUTE: 'resume', + STEPS: { CONFIRM_RESUME: 'confirm-resume' }, + }, + ROBOT_IN_MOTION: { + ROUTE: 'robot-in-motion', + STEPS: { + IN_MOTION: 'in-motion', + }, + }, + ROBOT_RESUMING: { + ROUTE: 'robot-resuming', + STEPS: { + RESUMING: 'resuming', + }, + }, + OPTION_SELECTION: { + ROUTE: 'option-selection', + STEPS: { SELECT: 'select' }, + }, +} as const + +const { + BEFORE_BEGINNING, + OPTION_SELECTION, + RESUME, + ROBOT_RESUMING, + ROBOT_IN_MOTION, + DROP_TIP, + REFILL_AND_RESUME, + IGNORE_AND_RESUME, + CANCEL_RUN, +} = RECOVERY_MAP + +// The deterministic ordering of steps for a given route. +export const STEP_ORDER: StepOrder = { + [BEFORE_BEGINNING.ROUTE]: [BEFORE_BEGINNING.STEPS.RECOVERY_DESCRIPTION], + [OPTION_SELECTION.ROUTE]: [OPTION_SELECTION.STEPS.SELECT], + [RESUME.ROUTE]: [RESUME.STEPS.CONFIRM_RESUME], + [ROBOT_IN_MOTION.ROUTE]: [ROBOT_IN_MOTION.STEPS.IN_MOTION], + [ROBOT_RESUMING.ROUTE]: [ROBOT_RESUMING.STEPS.RESUMING], + [DROP_TIP.ROUTE]: [], + [REFILL_AND_RESUME.ROUTE]: [], + [IGNORE_AND_RESUME.ROUTE]: [], + [CANCEL_RUN.ROUTE]: [], +} + +export const INVALID = 'INVALID' as const + +/** + * Styling + */ + +// These colors are temp and will be removed as design does design things. +export const NON_DESIGN_SANCTIONED_COLOR_1 = '#56FF00' +export const NON_DESIGN_SANCTIONED_COLOR_2 = '#FF00EF' + +export const NON_SANCTIONED_RECOVERY_COLOR_STYLE_PRIMARY = css` + background-color: ${NON_DESIGN_SANCTIONED_COLOR_1}; + + &:active { + background-color: ${NON_DESIGN_SANCTIONED_COLOR_2}; + } + &:hover { + background-color: ${NON_DESIGN_SANCTIONED_COLOR_1}; + } + &:focus { + background-color: ${NON_DESIGN_SANCTIONED_COLOR_2}; + } +` + +export const NON_SANCTIONED_RECOVERY_COLOR_STYLE_SECONDARY = css` + background-color: ${NON_DESIGN_SANCTIONED_COLOR_2}; + + &:active { + background-color: ${NON_DESIGN_SANCTIONED_COLOR_2}; + } + &:hover { + background-color: ${NON_DESIGN_SANCTIONED_COLOR_1}; + } + &:focus { + background-color: ${NON_DESIGN_SANCTIONED_COLOR_2}; + } +` + +export const BODY_TEXT_STYLE = css` + ${TYPOGRAPHY.bodyTextRegular}; +` + +export const ODD_SECTION_TITLE_STYLE = css` + margin-bottom: ${SPACING.spacing16}; +` diff --git a/app/src/organisms/ErrorRecoveryFlows/index.tsx b/app/src/organisms/ErrorRecoveryFlows/index.tsx new file mode 100644 index 00000000000..2824b85fbe0 --- /dev/null +++ b/app/src/organisms/ErrorRecoveryFlows/index.tsx @@ -0,0 +1,109 @@ +import * as React from 'react' +import { createPortal } from 'react-dom' +import { useSelector } from 'react-redux' + +import { + BORDERS, + COLORS, + DIRECTION_COLUMN, + Flex, + POSITION_ABSOLUTE, +} from '@opentrons/components' + +import { getIsOnDevice } from '../../redux/config' +import { getTopPortalEl } from '../../App/portal' +import { BeforeBeginning } from './BeforeBeginning' +import { SelectRecoveryOption, ResumeRun } from './RecoveryOptions' +import { ErrorRecoveryHeader } from './ErrorRecoveryHeader' +import { RecoveryInProgress } from './RecoveryInProgress' +import { getErrorKind, useRouteUpdateActions } from './utils' +import { RECOVERY_MAP } from './constants' + +import type { IRecoveryMap, RecoveryContentProps } from './types' + +interface ErrorRecoveryProps { + onComplete: () => void + errorType?: string +} +export function ErrorRecoveryFlows({ + onComplete, + errorType, +}: ErrorRecoveryProps): JSX.Element { + /** + * Recovery Route: A logically-related collection of recovery steps or a single step if unrelated to any existing recovery route. + * Recovery Step: Analogous to a "step" in other wizard flows. + */ + const [recoveryMap, setRecoveryMap] = React.useState({ + route: RECOVERY_MAP.BEFORE_BEGINNING.ROUTE, + step: RECOVERY_MAP.BEFORE_BEGINNING.STEPS.RECOVERY_DESCRIPTION, + }) + + const errorKind = getErrorKind(errorType) + const isOnDevice = useSelector(getIsOnDevice) + + const routeUpdateActions = useRouteUpdateActions({ + recoveryMap, + setRecoveryMap, + }) + + return ( + + ) +} + +function ErrorRecoveryComponent(props: RecoveryContentProps): JSX.Element { + return createPortal( + + + + , + getTopPortalEl() + ) +} + +export function ErrorRecoveryContent(props: RecoveryContentProps): JSX.Element { + const buildBeforeBeginning = (): JSX.Element => { + return + } + + const buildSelectRecoveryOption = (): JSX.Element => { + return + } + + const buildRecoveryInProgress = (): JSX.Element => { + return + } + + const buildResumeRun = (): JSX.Element => { + return + } + + switch (props.recoveryMap.route) { + case RECOVERY_MAP.BEFORE_BEGINNING.ROUTE: + return buildBeforeBeginning() + case RECOVERY_MAP.OPTION_SELECTION.ROUTE: + return buildSelectRecoveryOption() + case RECOVERY_MAP.RESUME.ROUTE: + return buildResumeRun() + case RECOVERY_MAP.ROBOT_IN_MOTION.ROUTE: + case RECOVERY_MAP.ROBOT_RESUMING.ROUTE: + return buildRecoveryInProgress() + default: + return buildSelectRecoveryOption() + } +} diff --git a/app/src/organisms/ErrorRecoveryFlows/types.ts b/app/src/organisms/ErrorRecoveryFlows/types.ts new file mode 100644 index 00000000000..51a3f4deb28 --- /dev/null +++ b/app/src/organisms/ErrorRecoveryFlows/types.ts @@ -0,0 +1,58 @@ +import type { ERROR_KINDS, RECOVERY_MAP, INVALID } from './constants' +import type { UseRouteUpdateActionsResult } from './utils' + +export type InvalidStep = typeof INVALID +export type RecoveryRoute = typeof RECOVERY_MAP[keyof typeof RECOVERY_MAP]['ROUTE'] +export type RobotMovingRoute = + | typeof RECOVERY_MAP['ROBOT_IN_MOTION']['ROUTE'] + | typeof RECOVERY_MAP['ROBOT_RESUMING']['ROUTE'] +export type ErrorKind = keyof typeof ERROR_KINDS + +interface RecoveryMapDetails { + ROUTE: string + STEPS: Record + STEP_ORDER: RouteStep +} + +export type RecoveryMap = Record +export type StepOrder = { + [K in RecoveryRoute]: RouteStep[] +} + +type RecoveryStep< + K extends keyof RecoveryMap +> = RecoveryMap[K]['STEPS'][keyof RecoveryMap[K]['STEPS']] + +type RobotInMotionStep = RecoveryStep<'ROBOT_IN_MOTION'> +type RobotResumingStep = RecoveryStep<'ROBOT_RESUMING'> +type BeforeBeginningStep = RecoveryStep<'BEFORE_BEGINNING'> +type CancelRunStep = RecoveryStep<'CANCEL_RUN'> +type DropTipStep = RecoveryStep<'DROP_TIP'> +type IgnoreAndResumeStep = RecoveryStep<'IGNORE_AND_RESUME'> +type RefillAndResumeStep = RecoveryStep<'REFILL_AND_RESUME'> +type ResumeStep = RecoveryStep<'RESUME'> +type OptionSelectionStep = RecoveryStep<'OPTION_SELECTION'> + +export type RouteStep = + | RobotInMotionStep + | RobotResumingStep + | BeforeBeginningStep + | CancelRunStep + | DropTipStep + | IgnoreAndResumeStep + | ResumeStep + | OptionSelectionStep + | RefillAndResumeStep + +export interface IRecoveryMap { + route: RecoveryRoute + step: RouteStep +} + +export interface RecoveryContentProps { + errorKind: ErrorKind + isOnDevice: boolean + recoveryMap: IRecoveryMap + routeUpdateActions: UseRouteUpdateActionsResult + onComplete: () => void +} diff --git a/app/src/organisms/ErrorRecoveryFlows/utils.ts b/app/src/organisms/ErrorRecoveryFlows/utils.ts new file mode 100644 index 00000000000..3a6c23e73dd --- /dev/null +++ b/app/src/organisms/ErrorRecoveryFlows/utils.ts @@ -0,0 +1,168 @@ +import * as React from 'react' +import { useTranslation } from 'react-i18next' +import last from 'lodash/last' +import head from 'lodash/head' + +import { RECOVERY_MAP, ERROR_KINDS, INVALID, STEP_ORDER } from './constants' + +import type { + RouteStep, + IRecoveryMap, + RecoveryRoute, + ErrorKind, + RobotMovingRoute, +} from './types' + +export function useErrorName(errorKind: ErrorKind): string { + const { t } = useTranslation('error_recovery') + + switch (errorKind) { + default: + return t('general_error') + } +} + +// The generalized error message shown to the user in select locations. +export function useErrorMessage(errorKind: ErrorKind): string { + const { t } = useTranslation('error_recovery') + + switch (errorKind) { + default: + return t('general_error_message') + } +} + +export function getErrorKind(errorType?: string): ErrorKind { + switch (errorType) { + default: + return ERROR_KINDS.GENERAL_ERROR + } +} + +export interface GetRouteUpdateActionsParams { + recoveryMap: IRecoveryMap + setRecoveryMap: (recoveryMap: IRecoveryMap) => void +} +export interface UseRouteUpdateActionsResult { + goBackPrevStep: () => void + proceedNextStep: () => void + proceedToRoute: (route: RecoveryRoute) => void + setRobotInMotion: (inMotion: boolean, movingRoute?: RobotMovingRoute) => void +} +// Utilities related to routing within the error recovery flows. +export function useRouteUpdateActions({ + recoveryMap, + setRecoveryMap, +}: GetRouteUpdateActionsParams): UseRouteUpdateActionsResult { + const { route: currentRoute, step: currentStep } = recoveryMap + const [stashedMap, setStashedMap] = React.useState(null) + const { OPTION_SELECTION, ROBOT_IN_MOTION } = RECOVERY_MAP + + // Redirect to the previous step for the current route if it exists, otherwise redirects to the option selection route. + const goBackPrevStep = React.useCallback((): void => { + const { getPrevStep } = getRecoveryRouteNavigation(currentRoute) + const updatedStep = getPrevStep(currentStep) + + if (updatedStep === INVALID) { + setRecoveryMap({ + route: OPTION_SELECTION.ROUTE, + step: OPTION_SELECTION.STEPS.SELECT, + }) + } else { + setRecoveryMap({ route: currentRoute, step: updatedStep }) + } + }, [currentStep, currentRoute]) + + // Redirect to the next step for the current route if it exists, otherwise redirects to the option selection route. + const proceedNextStep = React.useCallback((): void => { + const { getNextStep } = getRecoveryRouteNavigation(currentRoute) + const updatedStep = getNextStep(currentStep) + + if (updatedStep === INVALID) { + setRecoveryMap({ + route: OPTION_SELECTION.ROUTE, + step: OPTION_SELECTION.STEPS.SELECT, + }) + } else { + setRecoveryMap({ route: currentRoute, step: updatedStep }) + } + }, [currentStep, currentRoute]) + + // Redirect to a specific route. + const proceedToRoute = React.useCallback((route: RecoveryRoute): void => { + const newFlowSteps = STEP_ORDER[route] + + setRecoveryMap({ + route, + step: head(newFlowSteps) as RouteStep, + }) + }, []) + + // Stashes the current map then sets the current map to robot in motion. Restores the map after motion completes. + const setRobotInMotion = React.useCallback( + (inMotion: boolean, robotMovingRoute?: RobotMovingRoute): void => { + if (inMotion) { + if (stashedMap == null) { + setStashedMap({ route: currentRoute, step: currentStep }) + } + const route = robotMovingRoute ?? ROBOT_IN_MOTION.ROUTE + const step = + robotMovingRoute != null + ? (head(STEP_ORDER[robotMovingRoute]) as RouteStep) + : ROBOT_IN_MOTION.STEPS.IN_MOTION + + setRecoveryMap({ + route, + step, + }) + } else { + if (stashedMap != null) { + setRecoveryMap(stashedMap) + setStashedMap(null) + } else { + setRecoveryMap({ + route: OPTION_SELECTION.ROUTE, + step: OPTION_SELECTION.STEPS.SELECT, + }) + } + } + }, + [currentRoute, currentStep, stashedMap] + ) + + return { goBackPrevStep, proceedNextStep, proceedToRoute, setRobotInMotion } +} + +interface IRecoveryRouteNavigation { + getNextStep: (step: RouteStep) => RouteStep | typeof INVALID + getPrevStep: (step: RouteStep) => RouteStep | typeof INVALID +} +export function getRecoveryRouteNavigation( + route: RecoveryRoute +): IRecoveryRouteNavigation { + const getNextStep = (step: RouteStep): RouteStep => { + const routeSteps = STEP_ORDER[route] + const isStepFinalStep = step === last(routeSteps) + + if (isStepFinalStep) { + return INVALID + } else { + const stepIndex = routeSteps.indexOf(step) + return stepIndex !== -1 ? routeSteps[stepIndex + 1] : INVALID + } + } + + const getPrevStep = (step: RouteStep): RouteStep | typeof INVALID => { + const routeSteps = STEP_ORDER[route] + const isStepFirstStep = step === head(routeSteps) + + if (isStepFirstStep) { + return INVALID + } else { + const stepIndex = routeSteps.indexOf(step) + return stepIndex !== -1 ? routeSteps[stepIndex - 1] : INVALID + } + } + + return { getNextStep, getPrevStep } +} diff --git a/app/src/organisms/FirmwareUpdateModal/UpdateResultsModal.tsx b/app/src/organisms/FirmwareUpdateModal/UpdateResultsModal.tsx index 614f3384419..967d9a0632f 100644 --- a/app/src/organisms/FirmwareUpdateModal/UpdateResultsModal.tsx +++ b/app/src/organisms/FirmwareUpdateModal/UpdateResultsModal.tsx @@ -1,6 +1,5 @@ import * as React from 'react' import { useTranslation, Trans } from 'react-i18next' -import { getPipetteModelSpecs } from '@opentrons/shared-data' import { ALIGN_CENTER, BORDERS, @@ -14,8 +13,9 @@ import { } from '@opentrons/components' import { SmallButton } from '../../atoms/buttons' import { Modal } from '../../molecules/Modal' +import { usePipetteModelSpecs } from '../../resources/instruments/hooks' -import type { InstrumentData } from '@opentrons/api-client' +import type { InstrumentData, PipetteData } from '@opentrons/api-client' import type { ModalHeaderBaseProps } from '../../molecules/Modal/types' interface UpdateResultsModalProps { @@ -29,19 +29,23 @@ export function UpdateResultsModal( props: UpdateResultsModalProps ): JSX.Element { const { isSuccess, shouldExit, onClose, instrument } = props - const { i18n, t } = useTranslation(['firmware_update', 'shared']) + const { i18n, t } = useTranslation(['firmware_update', 'shared', 'branded']) const updateFailedHeader: ModalHeaderBaseProps = { title: t('update_failed'), iconName: 'ot-alert', iconColor: COLORS.red50, } + + const pipetteDisplayName = usePipetteModelSpecs( + (instrument as PipetteData)?.instrumentModel + )?.displayName + let instrumentName = 'instrument' if (instrument?.ok) { instrumentName = instrument?.instrumentType === 'pipette' - ? getPipetteModelSpecs(instrument.instrumentModel)?.displayName ?? - 'pipette' + ? pipetteDisplayName ?? 'pipette' : 'Flex Gripper' } return ( @@ -50,7 +54,7 @@ export function UpdateResultsModal( - {t('download_logs')} + {t('branded:firmware_update_download_logs')} { subsystem: 'pipette_right', } }) - it('renders text', () => { + it('renders pipette text', () => { const { getByText } = render(props) getByText('Updating pipette firmware...') }) + it('renders Hepa/UV text', () => { + props = { + subsystem: 'hepa_uv', + } + const { getByText } = render(props) + getByText('Updating HEPA/UV Module firmware...') + }) }) diff --git a/app/src/organisms/GripperCard/AboutGripperSlideout.tsx b/app/src/organisms/GripperCard/AboutGripperSlideout.tsx index 9bd6f8f6706..8eea030d615 100644 --- a/app/src/organisms/GripperCard/AboutGripperSlideout.tsx +++ b/app/src/organisms/GripperCard/AboutGripperSlideout.tsx @@ -22,11 +22,11 @@ export const AboutGripperSlideout = ( props: AboutGripperSlideoutProps ): JSX.Element | null => { const { serialNumber, firmwareVersion, isExpanded, onCloseClick } = props - const { i18n, t } = useTranslation(['device_details', 'shared']) + const { i18n, t } = useTranslation(['device_details', 'shared', 'branded']) return ( { if (createdMaintenanceRunId == null) { createMaintenanceRun({}) @@ -108,7 +108,7 @@ export const BeforeBeginning = ( displayName: t('hex_screwdriver'), subtitle: t('provided_with_robot_use_right_size'), }, - [GRIPPER_LOADNAME]: { displayName: t('gripper') }, + [GRIPPER_LOADNAME]: { displayName: t('branded:gripper') }, } const { bodyI18nKey, equipmentLoadNames } = INFO_BY_FLOW_TYPE[flowType] diff --git a/app/src/organisms/GripperWizardFlows/MountGripper.tsx b/app/src/organisms/GripperWizardFlows/MountGripper.tsx index 7e1636f6d05..a7049cf447d 100644 --- a/app/src/organisms/GripperWizardFlows/MountGripper.tsx +++ b/app/src/organisms/GripperWizardFlows/MountGripper.tsx @@ -58,7 +58,7 @@ export const MountGripper = ( props: GripperWizardStepProps ): JSX.Element | null => { const { proceed, isRobotMoving } = props - const { t } = useTranslation(['gripper_wizard_flows', 'shared']) + const { t } = useTranslation(['gripper_wizard_flows', 'shared', 'branded']) const isOnDevice = useSelector(getIsOnDevice) const [showUnableToDetect, setShowUnableToDetect] = React.useState(false) const [isPending, setIsPending] = React.useState(false) @@ -119,7 +119,7 @@ export const MountGripper = (
) : ( { const { proceed, successfulAction, isRobotMoving } = props - const { t, i18n } = useTranslation(['gripper_wizard_flows', 'shared']) + const { t, i18n } = useTranslation([ + 'gripper_wizard_flows', + 'shared', + 'branded', + ]) const isOnDevice = useSelector(getIsOnDevice) const infoByAction: { @@ -46,11 +50,11 @@ export const Success = ( } } = { [SUCCESSFULLY_ATTACHED_AND_CALIBRATED]: { - header: t('gripper_successfully_attached_and_calibrated'), + header: t('branded:gripper_successfully_attached_and_calibrated'), buttonText: i18n.format(t('shared:exit'), 'capitalize'), }, [SUCCESSFULLY_CALIBRATED]: { - header: t('gripper_successfully_calibrated'), + header: t('branded:gripper_successfully_calibrated'), buttonText: i18n.format(t('shared:exit'), 'capitalize'), }, [SUCCESSFULLY_ATTACHED]: { @@ -58,7 +62,7 @@ export const Success = ( buttonText: t('calibrate_gripper'), }, [SUCCESSFULLY_DETACHED]: { - header: t('gripper_successfully_detached'), + header: t('branded:gripper_successfully_detached'), buttonText: i18n.format(t('shared:exit'), 'capitalize'), }, } diff --git a/app/src/organisms/GripperWizardFlows/UnmountGripper.tsx b/app/src/organisms/GripperWizardFlows/UnmountGripper.tsx index c8e25bc0228..f0b2467e95d 100644 --- a/app/src/organisms/GripperWizardFlows/UnmountGripper.tsx +++ b/app/src/organisms/GripperWizardFlows/UnmountGripper.tsx @@ -51,7 +51,7 @@ export const UnmountGripper = ( props: GripperWizardStepProps ): JSX.Element | null => { const { proceed, isRobotMoving, goBack, chainRunCommands } = props - const { t } = useTranslation(['gripper_wizard_flows', 'shared']) + const { t } = useTranslation(['gripper_wizard_flows', 'shared', 'branded']) const isOnDevice = useSelector(getIsOnDevice) const [isPending, setIsPending] = React.useState(false) const { data: instrumentsQueryData, refetch } = useInstrumentsQuery({ @@ -100,7 +100,7 @@ export const UnmountGripper = ( return showGripperStillDetected ? ( ) : ( (false) const [errorMessage, setErrorMessage] = React.useState(null) - const { deleteMaintenanceRun } = useDeleteMaintenanceRunMutation({ - onSuccess: () => closeFlow(), - onError: () => closeFlow(), - }) + const handleClose = (): void => { + if (props?.onComplete != null) props.onComplete() + if (maintenanceRunData != null) { + deleteMaintenanceRun(maintenanceRunData?.data.id) + } + closeFlow() + } + + const { deleteMaintenanceRun } = useDeleteMaintenanceRunMutation({}) const handleCleanUpAndClose = (): void => { - setIsExiting(true) - if (maintenanceRunData?.data.id == null) { - closeFlow() - } else { + if (maintenanceRunData?.data.id == null) handleClose() + else { chainRunCommands( maintenanceRunData?.data.id, [{ commandType: 'home' as const, params: {} }], - true + false ) .then(() => { - deleteMaintenanceRun(maintenanceRunData?.data.id) - setIsExiting(false) - props.onComplete?.() + handleClose() }) .catch(error => { - console.error(error.message) - deleteMaintenanceRun(maintenanceRunData?.data.id) - setIsExiting(false) - props.onComplete?.() + setIsExiting(true) + setErrorMessage(error.message) }) } } @@ -156,6 +156,7 @@ export function GripperWizardFlows( isChainCommandMutationLoading || isCommandLoading || isExiting } handleCleanUpAndClose={handleCleanUpAndClose} + handleClose={handleClose} chainRunCommands={chainRunCommands} createRunCommand={createMaintenanceCommand} errorMessage={errorMessage} @@ -182,6 +183,7 @@ interface GripperWizardProps { setErrorMessage: (message: string | null) => void errorMessage: string | null handleCleanUpAndClose: () => void + handleClose: () => void chainRunCommands: ReturnType< typeof useChainMaintenanceCommands >['chainRunCommands'] @@ -198,6 +200,7 @@ export const GripperWizard = ( maintenanceRunId, createMaintenanceRun, handleCleanUpAndClose, + handleClose, chainRunCommands, attachedGripper, isCreateLoading, @@ -275,6 +278,16 @@ export const GripperWizard = ( isRobotMoving={isRobotMoving} /> ) + } else if (isExiting && errorMessage != null) { + onExit = handleClose + modalContent = ( + + ) } else if (currentStep.section === SECTIONS.BEFORE_BEGINNING) { onExit = handleCleanUpAndClose modalContent = ( diff --git a/app/src/organisms/InstrumentMountItem/AttachedInstrumentMountItem.tsx b/app/src/organisms/InstrumentMountItem/AttachedInstrumentMountItem.tsx index 84abd47809d..042502275be 100644 --- a/app/src/organisms/InstrumentMountItem/AttachedInstrumentMountItem.tsx +++ b/app/src/organisms/InstrumentMountItem/AttachedInstrumentMountItem.tsx @@ -1,22 +1,23 @@ import * as React from 'react' import { useHistory } from 'react-router-dom' +import { SINGLE_MOUNT_PIPETTES } from '@opentrons/shared-data' + import { - getGripperDisplayName, - getPipetteModelSpecs, - GripperModel, - PipetteModel, - SINGLE_MOUNT_PIPETTES, -} from '@opentrons/shared-data' + useGripperDisplayName, + usePipetteModelSpecs, +} from '../../resources/instruments/hooks' import { ChoosePipette } from '../PipetteWizardFlows/ChoosePipette' import { FLOWS } from '../PipetteWizardFlows/constants' -import { PipetteWizardFlows } from '../PipetteWizardFlows' -import { GripperWizardFlows } from '../GripperWizardFlows' import { GRIPPER_FLOW_TYPES } from '../GripperWizardFlows/constants' import { LabeledMount } from './LabeledMount' + import type { InstrumentData } from '@opentrons/api-client' +import type { GripperModel, PipetteModel } from '@opentrons/shared-data' import type { Mount } from '../../redux/pipettes/types' import type { SelectablePipettes } from '../PipetteWizardFlows/types' +import type { GripperWizardFlows } from '../GripperWizardFlows' +import type { PipetteWizardFlows } from '../PipetteWizardFlows' interface AttachedInstrumentMountItemProps { mount: Mount | 'extension' @@ -62,22 +63,27 @@ export function AttachedInstrumentMountItem( history.push(`/instruments/${mount}`) } } - let displayName - if (attachedInstrument != null && attachedInstrument.ok) { - displayName = - attachedInstrument?.mount !== 'extension' - ? getPipetteModelSpecs( - attachedInstrument?.instrumentModel as PipetteModel - )?.displayName - : getGripperDisplayName( - attachedInstrument?.instrumentModel as GripperModel - ) - } + + const instrumentModel = attachedInstrument?.ok + ? attachedInstrument.instrumentModel + : null + + const pipetteDisplayName = + usePipetteModelSpecs(instrumentModel as PipetteModel)?.displayName ?? null + const gripperDisplayName = useGripperDisplayName( + instrumentModel as GripperModel + ) + + const displayName = + attachedInstrument?.ok && attachedInstrument?.mount === 'extension' + ? gripperDisplayName + : pipetteDisplayName + return ( <> {showChoosePipetteModal ? ( diff --git a/app/src/organisms/InstrumentMountItem/LabeledMount.tsx b/app/src/organisms/InstrumentMountItem/LabeledMount.tsx index ae69c9331b3..65d562543af 100644 --- a/app/src/organisms/InstrumentMountItem/LabeledMount.tsx +++ b/app/src/organisms/InstrumentMountItem/LabeledMount.tsx @@ -40,7 +40,7 @@ interface LabeledMountProps { export function LabeledMount(props: LabeledMountProps): JSX.Element { const { t } = useTranslation('device_details') const { mount, instrumentName, handleClick } = props - const ninetySixDisplayName = 'Flex 96-Channel 1000 μL' + const isNinetySixChannel = instrumentName?.includes('96-Channel') ?? false return ( @@ -62,9 +62,7 @@ export function LabeledMount(props: LabeledMountProps): JSX.Element { fontSize={TYPOGRAPHY.fontSize28} width="15.625rem" > - {instrumentName === ninetySixDisplayName - ? t('left_right') - : t('mount', { side: mount })} + {isNinetySixChannel ? t('left_right') : t('mount', { side: mount })} @@ -117,9 +124,7 @@ export function ProtocolInstrumentMountItem( )} - {mount === 'extension' - ? getGripperDisplayName(speccedName as GripperModel) - : getPipetteNameSpecs(speccedName as PipetteName)?.displayName} + {mount === 'extension' ? gripperDisplayName : pipetteDisplayName} diff --git a/app/src/organisms/InterventionModal/MoveLabwareInterventionContent.tsx b/app/src/organisms/InterventionModal/MoveLabwareInterventionContent.tsx index e6ae7740ffb..9a932bb697d 100644 --- a/app/src/organisms/InterventionModal/MoveLabwareInterventionContent.tsx +++ b/app/src/organisms/InterventionModal/MoveLabwareInterventionContent.tsx @@ -35,6 +35,7 @@ import { getModuleType, getOccludedSlotCountForModule, } from '@opentrons/shared-data' + import { getRunLabwareRenderInfo, getRunModuleRenderInfo, @@ -47,8 +48,9 @@ import { getLoadedLabware, getLoadedModule, } from '../CommandText/utils/accessors' +import { useNotifyDeckConfigurationQuery } from '../../resources/deck_configuration' + import type { RunData } from '@opentrons/api-client' -import { useDeckConfigurationQuery } from '@opentrons/react-api-client' const LABWARE_DESCRIPTION_STYLE = css` flex-direction: ${DIRECTION_COLUMN}; @@ -119,7 +121,7 @@ export function MoveLabwareInterventionContent({ const analysisCommands = analysis?.commands ?? [] const labwareDefsByUri = getLoadedLabwareDefinitionsByUri(analysisCommands) const deckDef = getDeckDefFromRobotType(robotType) - const deckConfig = useDeckConfigurationQuery().data ?? [] + const deckConfig = useNotifyDeckConfigurationQuery().data ?? [] const moduleRenderInfo = getRunModuleRenderInfo( run, diff --git a/app/src/organisms/InterventionModal/__fixtures__/index.ts b/app/src/organisms/InterventionModal/__fixtures__/index.ts index b6d631f4c97..2611fe19b03 100644 --- a/app/src/organisms/InterventionModal/__fixtures__/index.ts +++ b/app/src/organisms/InterventionModal/__fixtures__/index.ts @@ -188,6 +188,7 @@ export const mockRunData: RunData = { pipettes: [], labware: [mockLabwareOnModule, mockLabwareOnSlot, mockLabwareOffDeck], modules: [mockModule], + runTimeParameters: [], } export const mockLabwareRenderInfo = [ diff --git a/app/src/organisms/InterventionModal/__tests__/utils.test.ts b/app/src/organisms/InterventionModal/__tests__/utils.test.ts index b14f510a29f..eca5086cd9d 100644 --- a/app/src/organisms/InterventionModal/__tests__/utils.test.ts +++ b/app/src/organisms/InterventionModal/__tests__/utils.test.ts @@ -2,7 +2,7 @@ import deepClone from 'lodash/cloneDeep' import { describe, it, expect, vi, beforeEach } from 'vitest' import { getSlotHasMatingSurfaceUnitVector, - ot2DeckDefV4, + ot2DeckDefV5, } from '@opentrons/shared-data' import { @@ -137,7 +137,7 @@ describe('getRunLabwareRenderInfo', () => { const res = getRunLabwareRenderInfo( mockRunData, mockLabwareDefinitionsByUri, - ot2DeckDefV4 as any + ot2DeckDefV5 as any ) const labwareInfo = res[0] expect(labwareInfo).toBeTruthy() @@ -154,7 +154,7 @@ describe('getRunLabwareRenderInfo', () => { const res = getRunLabwareRenderInfo( mockRunData, mockLabwareDefinitionsByUri, - ot2DeckDefV4 as any + ot2DeckDefV5 as any ) expect(res).toHaveLength(1) // the offdeck labware still gets added because the mating surface doesn't exist for offdeck labware }) @@ -163,7 +163,7 @@ describe('getRunLabwareRenderInfo', () => { const res = getRunLabwareRenderInfo( mockRunData, mockLabwareDefinitionsByUri, - ot2DeckDefV4 as any + ot2DeckDefV5 as any ) expect(res).toHaveLength(2) const labwareInfo = res.find( @@ -172,7 +172,7 @@ describe('getRunLabwareRenderInfo', () => { expect(labwareInfo).toBeTruthy() expect(labwareInfo?.x).toEqual(0) expect(labwareInfo?.y).toEqual( - ot2DeckDefV4.cornerOffsetFromOrigin[1] - + ot2DeckDefV5.cornerOffsetFromOrigin[1] - mockLabwareDefinition.dimensions.yDimension ) }) @@ -189,7 +189,7 @@ describe('getRunLabwareRenderInfo', () => { const res = getRunLabwareRenderInfo( { labware: [mockBadSlotLabware] } as any, mockLabwareDefinitionsByUri, - ot2DeckDefV4 as any + ot2DeckDefV5 as any ) expect(res[0].x).toEqual(0) @@ -207,7 +207,7 @@ describe('getCurrentRunModuleRenderInfo', () => { it('returns run module render info with nested labware', () => { const res = getRunModuleRenderInfo( mockRunData, - ot2DeckDefV4 as any, + ot2DeckDefV5 as any, mockLabwareDefinitionsByUri ) const moduleInfo = res[0] @@ -228,7 +228,7 @@ describe('getCurrentRunModuleRenderInfo', () => { const res = getRunModuleRenderInfo( mockRunDataNoNesting, - ot2DeckDefV4 as any, + ot2DeckDefV5 as any, mockLabwareDefinitionsByUri ) @@ -245,7 +245,7 @@ describe('getCurrentRunModuleRenderInfo', () => { const res = getRunModuleRenderInfo( mockRunDataWithTC, - ot2DeckDefV4 as any, + ot2DeckDefV5 as any, mockLabwareDefinitionsByUri ) @@ -270,7 +270,7 @@ describe('getCurrentRunModuleRenderInfo', () => { const res = getRunModuleRenderInfo( mockRunDataWithBadModuleSlot, - ot2DeckDefV4 as any, + ot2DeckDefV5 as any, mockLabwareDefinitionsByUri ) diff --git a/app/src/organisms/LabwareCard/index.tsx b/app/src/organisms/LabwareCard/index.tsx index 708639711b2..2413b10e4fc 100644 --- a/app/src/organisms/LabwareCard/index.tsx +++ b/app/src/organisms/LabwareCard/index.tsx @@ -30,7 +30,7 @@ export interface LabwareCardProps { } export function LabwareCard(props: LabwareCardProps): JSX.Element { - const { t } = useTranslation('labware_landing') + const { t } = useTranslation(['labware_landing', 'branded']) const { definition, modified, filename } = props.labware const apiName = definition.parameters.loadName const displayName = definition?.metadata.displayName @@ -100,7 +100,7 @@ export function LabwareCard(props: LabwareCardProps): JSX.Element { id="LabwareCard_opentronsDef" marginLeft={SPACING.spacing4} > - {t('opentrons_def')} + {t('branded:opentrons_def')}
)} diff --git a/app/src/organisms/LabwareDetails/index.tsx b/app/src/organisms/LabwareDetails/index.tsx index 4f0cc83b3a4..7787e13f57f 100644 --- a/app/src/organisms/LabwareDetails/index.tsx +++ b/app/src/organisms/LabwareDetails/index.tsx @@ -65,7 +65,7 @@ export interface LabwareDetailsProps { } export function LabwareDetails(props: LabwareDetailsProps): JSX.Element { - const { t } = useTranslation('labware_landing') + const { t } = useTranslation(['labware_landing', 'branded']) const { definition, modified, filename } = props.labware const { metadata, parameters, brand, wells, ordering } = definition const apiName = definition.parameters.loadName @@ -129,7 +129,7 @@ export function LabwareDetails(props: LabwareDetailsProps): JSX.Element { id="LabwareDetails_opentronsDef" marginLeft={SPACING.spacing4} > - {t('opentrons_def')} + {t('branded:opentrons_def')}
)} diff --git a/app/src/organisms/LabwareOffsetTabs/index.tsx b/app/src/organisms/LabwareOffsetTabs/index.tsx index 82c1fb0741d..1d0a2d20092 100644 --- a/app/src/organisms/LabwareOffsetTabs/index.tsx +++ b/app/src/organisms/LabwareOffsetTabs/index.tsx @@ -42,7 +42,7 @@ export function LabwareOffsetTabs({ flexDirection={DIRECTION_COLUMN} {...styleProps} > - + setCurrentTab('table')} diff --git a/app/src/organisms/LabwarePositionCheck/AttachProbe.tsx b/app/src/organisms/LabwarePositionCheck/AttachProbe.tsx index 5f66b98a8cf..9cf7f86f375 100644 --- a/app/src/organisms/LabwarePositionCheck/AttachProbe.tsx +++ b/app/src/organisms/LabwarePositionCheck/AttachProbe.tsx @@ -96,7 +96,11 @@ export const AttachProbe = (props: AttachProbeProps): JSX.Element | null => { const verifyCommands: CreateCommand[] = [ { commandType: 'verifyTipPresence', - params: { pipetteId: pipetteId, expectedState: 'present' }, + params: { + pipetteId: pipetteId, + expectedState: 'present', + followSingularSensor: 'primary', + }, }, ] const homeCommands: CreateCommand[] = [ diff --git a/app/src/organisms/LabwarePositionCheck/FatalErrorModal.tsx b/app/src/organisms/LabwarePositionCheck/FatalErrorModal.tsx index 699d4512298..ddeeb006ce6 100644 --- a/app/src/organisms/LabwarePositionCheck/FatalErrorModal.tsx +++ b/app/src/organisms/LabwarePositionCheck/FatalErrorModal.tsx @@ -33,7 +33,7 @@ interface FatalErrorModalProps { } export function FatalErrorModal(props: FatalErrorModalProps): JSX.Element { const { errorMessage, shouldUseMetalProbe, onClose } = props - const { t } = useTranslation(['labware_position_check', 'shared']) + const { t } = useTranslation(['labware_position_check', 'shared', 'branded']) return createPortal( ) : null} - {t('shared:help_us_improve_send_error_report', { + {t('branded:help_us_improve_send_error_report', { support_email: SUPPORT_EMAIL, })} diff --git a/app/src/organisms/LabwarePositionCheck/PrepareSpace.tsx b/app/src/organisms/LabwarePositionCheck/PrepareSpace.tsx index 0ffb3bd6147..da886ccaba1 100644 --- a/app/src/organisms/LabwarePositionCheck/PrepareSpace.tsx +++ b/app/src/organisms/LabwarePositionCheck/PrepareSpace.tsx @@ -27,9 +27,9 @@ import { import { getIsOnDevice } from '../../redux/config' import { SmallButton } from '../../atoms/buttons' import { NeedHelpLink } from '../CalibrationPanels' +import { useNotifyDeckConfigurationQuery } from '../../resources/deck_configuration' import type { CheckLabwareStep } from './types' -import { useDeckConfigurationQuery } from '@opentrons/react-api-client' const LPC_HELP_LINK_URL = 'https://support.opentrons.com/s/article/How-Labware-Offsets-work-on-the-OT-2' @@ -71,7 +71,7 @@ export const PrepareSpace = (props: PrepareSpaceProps): JSX.Element | null => { const { location, labwareDef, protocolData, header, body, robotType } = props const isOnDevice = useSelector(getIsOnDevice) - const deckConfig = useDeckConfigurationQuery().data ?? [] + const deckConfig = useNotifyDeckConfigurationQuery().data ?? [] if (protocolData == null || robotType == null) return null diff --git a/app/src/organisms/ModuleCard/ErrorInfo.tsx b/app/src/organisms/ModuleCard/ErrorInfo.tsx index 75158e7010f..d8bb5e28b6e 100644 --- a/app/src/organisms/ModuleCard/ErrorInfo.tsx +++ b/app/src/organisms/ModuleCard/ErrorInfo.tsx @@ -29,7 +29,7 @@ interface ErrorInfoProps { } export function ErrorInfo(props: ErrorInfoProps): JSX.Element | null { const { attachedModule } = props - const { t } = useTranslation(['device_details', 'shared']) + const { t } = useTranslation(['device_details', 'shared', 'branded']) const [showErrorDetails, setShowErrorDetails] = React.useState(false) let isError: boolean = false @@ -92,7 +92,7 @@ export function ErrorInfo(props: ErrorInfoProps): JSX.Element | null { {errorDetails} ) : null} - {t('module_error_contact_support')} + {t('branded:module_error_contact_support')} diff --git a/app/src/organisms/ModuleCard/ModuleSetupModal.tsx b/app/src/organisms/ModuleCard/ModuleSetupModal.tsx index 8af56a5bcf4..21e3adb598a 100644 --- a/app/src/organisms/ModuleCard/ModuleSetupModal.tsx +++ b/app/src/organisms/ModuleCard/ModuleSetupModal.tsx @@ -26,7 +26,7 @@ interface ModuleSetupModalProps { export const ModuleSetupModal = (props: ModuleSetupModalProps): JSX.Element => { const { moduleDisplayName } = props - const { t, i18n } = useTranslation(['protocol_setup', 'shared']) + const { t, i18n } = useTranslation(['protocol_setup', 'shared', 'branded']) return createPortal( { width="50%" > - {t('modal_instructions')} + {t('branded:modal_instructions')} ) => { return renderWithProviders(, { i18nInstance: i18n, @@ -189,10 +190,12 @@ const render = (props: React.ComponentProps) => { } describe('ModuleCard', () => { - let dispatchApiRequest: DispatchApiRequestType let props: React.ComponentProps + let mockHandleModuleApiRequests: Mock beforeEach(() => { + mockHandleModuleApiRequests = vi.fn() + props = { module: mockMagneticModule, robotName: mockRobot.name, @@ -200,14 +203,11 @@ describe('ModuleCard', () => { attachPipetteRequired: false, calibratePipetteRequired: false, updatePipetteFWRequired: false, + handleModuleApiRequests: mockHandleModuleApiRequests, + latestRequestId: MOCK_LATEST_REQUEST_ID, } - dispatchApiRequest = vi.fn() vi.mocked(ErrorInfo).mockReturnValue(null) - vi.mocked(useDispatchApiRequest).mockReturnValue([ - dispatchApiRequest, - ['id'], - ]) vi.mocked(MagneticModuleData).mockReturnValue(
Mock Magnetic Module Data
) diff --git a/app/src/organisms/ModuleCard/__tests__/utils.test.ts b/app/src/organisms/ModuleCard/__tests__/utils.test.ts index 311c9676da0..5798efeb827 100644 --- a/app/src/organisms/ModuleCard/__tests__/utils.test.ts +++ b/app/src/organisms/ModuleCard/__tests__/utils.test.ts @@ -1,4 +1,5 @@ -import { describe, expect, it } from 'vitest' +import { describe, expect, it, vi, beforeEach } from 'vitest' +import { renderHook, act } from '@testing-library/react' import { mockHeaterShaker, @@ -9,7 +10,10 @@ import { mockThermocycler, mockThermocyclerGen2, } from '../../../redux/modules/__fixtures__' -import { getModuleCardImage } from '../utils' +import { getModuleCardImage, useModuleApiRequests } from '../utils' +import { useDispatchApiRequest } from '../../../redux/robot-api' + +vi.mock('../../../redux/robot-api') const mockThermocyclerGen2ClosedLid = { id: 'thermocycler_id2', @@ -83,3 +87,29 @@ describe('getModuleCardImage', () => { ) }) }) + +const updateModuleAction = { meta: { requestId: '12345' } } +const MOCK_ROBOT_NAME = 'MOCK_ROBOT' +const MOCK_SERIAL_NUMBER = '1234' +const mockDispatchApiRequest = () => updateModuleAction + +describe('useModuleApiRequests', () => { + beforeEach(() => { + vi.mocked(useDispatchApiRequest).mockReturnValue([ + mockDispatchApiRequest, + ] as any) + }) + + it('should dispatch an API request and update requestIdsBySerial on handleModuleApiRequests', () => { + const { result } = renderHook(() => useModuleApiRequests()) + + act(() => { + result.current[1](MOCK_ROBOT_NAME, MOCK_SERIAL_NUMBER) + }) + + expect(result.current[0](MOCK_SERIAL_NUMBER)).toEqual( + updateModuleAction.meta.requestId + ) + expect(result.current[0]('NON_EXISTENT_SERIAL')).toBeNull() + }) +}) diff --git a/app/src/organisms/ModuleCard/index.tsx b/app/src/organisms/ModuleCard/index.tsx index c2c42151eda..52f3ed99f65 100644 --- a/app/src/organisms/ModuleCard/index.tsx +++ b/app/src/organisms/ModuleCard/index.tsx @@ -1,7 +1,6 @@ import * as React from 'react' import { Trans, useTranslation } from 'react-i18next' import { useDispatch, useSelector } from 'react-redux' -import last from 'lodash/last' import { useHistory } from 'react-router-dom' import { @@ -31,9 +30,7 @@ import { import { RUN_STATUS_FINISHING, RUN_STATUS_RUNNING } from '@opentrons/api-client' import { OverflowBtn } from '../../atoms/MenuList/OverflowBtn' -import { updateModule } from '../../redux/modules' import { - useDispatchApiRequest, getRequestById, PENDING, FAILURE, @@ -85,6 +82,8 @@ interface ModuleCardProps { attachPipetteRequired: boolean calibratePipetteRequired: boolean updatePipetteFWRequired: boolean + latestRequestId: string | null + handleModuleApiRequests: (robotName: string, serialNumber: string) => void runId?: string slotName?: string } @@ -100,6 +99,8 @@ export const ModuleCard = (props: ModuleCardProps): JSX.Element | null => { attachPipetteRequired, calibratePipetteRequired, updatePipetteFWRequired, + latestRequestId, + handleModuleApiRequests, } = props const dispatch = useDispatch() const { @@ -115,13 +116,12 @@ export const ModuleCard = (props: ModuleCardProps): JSX.Element | null => { const [hasSecondary, setHasSecondary] = React.useState(false) const [showAboutModule, setShowAboutModule] = React.useState(false) const [showTestShake, setShowTestShake] = React.useState(false) - const [showHSWizard, setShowHSWizard] = React.useState(false) - const [showFWBanner, setShowFWBanner] = React.useState(true) - const [showCalModal, setShowCalModal] = React.useState(false) + const [showHSWizard, setShowHSWizard] = React.useState(false) + const [showFWBanner, setShowFWBanner] = React.useState(true) + const [showCalModal, setShowCalModal] = React.useState(false) const [targetProps, tooltipProps] = useHoverTooltip() const history = useHistory() - const [dispatchApiRequest, requestIds] = useDispatchApiRequest() const runStatus = useCurrentRunStatus({ onSettled: data => { if (data == null) { @@ -138,29 +138,31 @@ export const ModuleCard = (props: ModuleCardProps): JSX.Element | null => { (!attachPipetteRequired ?? false) && (!calibratePipetteRequired ?? false) && (!updatePipetteFWRequired ?? false) - const latestRequestId = last(requestIds) + const latestRequest = useSelector(state => - latestRequestId ? getRequestById(state, latestRequestId) : null + latestRequestId != null ? getRequestById(state, latestRequestId) : null ) - const isEstopNotDisengaged = useIsEstopNotDisengaged(robotName) - const handleCloseErrorModal = (): void => { - if (latestRequestId != null) { - dispatch(dismissRequest(latestRequestId)) - } + const hasUpdated = + !module.hasAvailableUpdate && latestRequest?.status === SUCCESS + const [showFirmwareToast, setShowFirmwareToast] = React.useState(hasUpdated) + const { makeToast } = useToaster() + if (showFirmwareToast) { + makeToast(t('firmware_updated_successfully'), SUCCESS_TOAST) + setShowFirmwareToast(false) } const handleFirmwareUpdateClick = (): void => { - robotName && - dispatchApiRequest(updateModule(robotName, module.serialNumber)) + robotName && handleModuleApiRequests(robotName, module.serialNumber) } - const { makeToast } = useToaster() - React.useEffect(() => { - if (!module.hasAvailableUpdate && latestRequest?.status === SUCCESS) { - makeToast(t('firmware_update_installation_successful'), SUCCESS_TOAST) + const isEstopNotDisengaged = useIsEstopNotDisengaged(robotName) + + const handleCloseErrorModal = (): void => { + if (latestRequestId != null) { + dispatch(dismissRequest(latestRequestId)) } - }, [module.hasAvailableUpdate, latestRequest?.status, makeToast, t]) + } const isPending = latestRequest?.status === PENDING const hotToTouch: IconProps = { name: 'ot-hot-to-touch' } diff --git a/app/src/organisms/ModuleCard/utils.ts b/app/src/organisms/ModuleCard/utils.ts index c80cfa2c4fe..dfd136bfcfc 100644 --- a/app/src/organisms/ModuleCard/utils.ts +++ b/app/src/organisms/ModuleCard/utils.ts @@ -1,3 +1,9 @@ +import * as React from 'react' +import last from 'lodash/last' + +import { useDispatchApiRequest } from '../../redux/robot-api' +import { updateModule } from '../../redux/modules' + import magneticModule from '../../assets/images/magnetic_module_gen_2_transparent.png' import temperatureModule from '../../assets/images/temp_deck_gen_2_transparent.png' import thermoModuleGen1Closed from '../../assets/images/thermocycler_closed.png' @@ -5,6 +11,7 @@ import thermoModuleGen1Opened from '../../assets/images/thermocycler_open_transp import heaterShakerModule from '../../assets/images/heater_shaker_module_transparent.png' import thermoModuleGen2Closed from '../../assets/images/thermocycler_gen_2_closed.png' import thermoModuleGen2Opened from '../../assets/images/thermocycler_gen_2_opened.png' + import type { AttachedModule } from '../../redux/modules/types' export function getModuleCardImage(attachedModule: AttachedModule): string { @@ -35,3 +42,58 @@ export function getModuleCardImage(attachedModule: AttachedModule): string { return 'unknown module model, this is an error' } } + +type RequestIdsBySerialNumber = Record +type HandleModuleApiRequestsType = (robotName: string, moduleId: string) => void +type GetLatestRequestIdType = (moduleId: string) => string | null + +export function useModuleApiRequests(): [ + GetLatestRequestIdType, + HandleModuleApiRequestsType +] { + const [dispatchApiRequest] = useDispatchApiRequest() + const [ + requestIdsBySerial, + setRequestIdsBySerial, + ] = React.useState({}) + + const handleModuleApiRequests = ( + robotName: string, + serialNumber: string + ): void => { + const action = dispatchApiRequest(updateModule(robotName, serialNumber)) + const { requestId } = action.meta + + if (requestId != null) { + if (serialNumber in requestIdsBySerial) { + setRequestIdsBySerial((prevState: RequestIdsBySerialNumber) => { + const existingRequestIds = prevState[serialNumber] || [] + return { + ...prevState, + [serialNumber]: [...existingRequestIds, requestId], + } + }) + } else { + setRequestIdsBySerial(prevState => { + return { + ...prevState, + [serialNumber]: [requestId], + } + }) + } + } + } + + const getLatestRequestId = React.useCallback( + (serialNumber: string): string | null => { + if (serialNumber in requestIdsBySerial) { + return last(requestIdsBySerial[serialNumber]) ?? null + } else { + return null + } + }, + [requestIdsBySerial] + ) + + return [getLatestRequestId, handleModuleApiRequests] +} diff --git a/app/src/organisms/ModuleWizardFlows/AttachProbe.tsx b/app/src/organisms/ModuleWizardFlows/AttachProbe.tsx index a4a324dc933..4a8f70656e4 100644 --- a/app/src/organisms/ModuleWizardFlows/AttachProbe.tsx +++ b/app/src/organisms/ModuleWizardFlows/AttachProbe.tsx @@ -1,12 +1,6 @@ import * as React from 'react' import { css } from 'styled-components' -import attachProbe1 from '../../assets/videos/pipette-wizard-flows/Pipette_Attach_Probe_1.webm' -import attachProbe8 from '../../assets/videos/pipette-wizard-flows/Pipette_Attach_Probe_8.webm' -import attachProbe96 from '../../assets/videos/pipette-wizard-flows/Pipette_Attach_Probe_96.webm' import { Trans, useTranslation } from 'react-i18next' -import { useDeckConfigurationQuery } from '@opentrons/react-api-client' -import { WASTE_CHUTE_CUTOUT, CreateCommand, LEFT } from '@opentrons/shared-data' -import { InProgressModal } from '../../molecules/InProgressModal/InProgressModal' import { Flex, RESPONSIVENESS, @@ -14,13 +8,26 @@ import { StyledText, TYPOGRAPHY, } from '@opentrons/components' +import { LEFT, WASTE_CHUTE_FIXTURES } from '@opentrons/shared-data' +import attachProbe1 from '../../assets/videos/pipette-wizard-flows/Pipette_Attach_Probe_1.webm' +import attachProbe8 from '../../assets/videos/pipette-wizard-flows/Pipette_Attach_Probe_8.webm' +import attachProbe96 from '../../assets/videos/pipette-wizard-flows/Pipette_Attach_Probe_96.webm' +import { InProgressModal } from '../../molecules/InProgressModal/InProgressModal' +import type { + CreateCommand, + DeckConfiguration, + CutoutId, + CutoutFixtureId, +} from '@opentrons/shared-data' import { Banner } from '../../atoms/Banner' import { GenericWizardTile } from '../../molecules/GenericWizardTile' import type { ModuleCalibrationWizardStepProps } from './types' interface AttachProbeProps extends ModuleCalibrationWizardStepProps { adapterId: string | null + deckConfig: DeckConfiguration + fixtureIdByCutoutId: { [cutoutId in CutoutId]?: CutoutFixtureId } } const BODY_STYLE = css` @@ -42,7 +49,8 @@ export const AttachProbe = (props: AttachProbeProps): JSX.Element | null => { attachedModule, attachedPipette, isOnDevice, - slotName, + deckConfig, + fixtureIdByCutoutId, } = props const { t, i18n } = useTranslation([ 'module_wizard_flows', @@ -65,12 +73,11 @@ export const AttachProbe = (props: AttachProbeProps): JSX.Element | null => { probeLocation = t('pipette_wizard_flows:ninety_six_probe_location') break } - const wasteChuteConflict = - slotName === 'C3' && attachedPipette.data.channels === 96 - const deckConfig = useDeckConfigurationQuery().data - const isWasteChuteOnDeck = - deckConfig?.find(fixture => fixture.cutoutId === WASTE_CHUTE_CUTOUT) ?? - false + const wasteChuteConflictWith96Channel = + 'cutoutC3' in fixtureIdByCutoutId && attachedPipette.data.channels === 96 + const isWasteChuteOnDeck = deckConfig.some(cc => + WASTE_CHUTE_FIXTURES.includes(cc.cutoutFixtureId) + ) const pipetteAttachProbeVid = ( @@ -101,7 +108,7 @@ export const AttachProbe = (props: AttachProbeProps): JSX.Element | null => { /> - {wasteChuteConflict && ( + {wasteChuteConflictWith96Channel && ( , - CreateMaintenanceRunData, - unknown - > - isCreateLoading: boolean - createdMaintenanceRunId: string | null -} +type BeforeBeginningProps = ModuleCalibrationWizardStepProps export const BeforeBeginning = ( props: BeforeBeginningProps ): JSX.Element | null => { - const { - proceed, - createMaintenanceRun, - isCreateLoading, - attachedModule, - maintenanceRunId, - createdMaintenanceRunId, - } = props + const { proceed, attachedModule } = props const { t } = useTranslation(['module_wizard_flows', 'shared']) - React.useEffect(() => { - if (createdMaintenanceRunId == null) { - createMaintenanceRun({}) - } - }, []) + const moduleDisplayName = getModuleDisplayName(attachedModule.moduleModel) let adapterLoadname: string @@ -103,13 +77,12 @@ export const BeforeBeginning = ( bodyText={ }} /> } proceedButtonText={t('start_setup')} - proceedIsDisabled={isCreateLoading || maintenanceRunId == null} proceed={proceed} /> ) diff --git a/app/src/organisms/ModuleWizardFlows/PlaceAdapter.tsx b/app/src/organisms/ModuleWizardFlows/PlaceAdapter.tsx index cd5c949d8ba..b5d5e5cf80d 100644 --- a/app/src/organisms/ModuleWizardFlows/PlaceAdapter.tsx +++ b/app/src/organisms/ModuleWizardFlows/PlaceAdapter.tsx @@ -16,7 +16,6 @@ import { TYPOGRAPHY, } from '@opentrons/components' import { - CreateCommand, getCalibrationAdapterLoadName, getModuleDisplayName, HEATERSHAKER_MODULE_TYPE, @@ -24,17 +23,34 @@ import { HEATERSHAKER_MODULE_MODELS, TEMPERATURE_MODULE_MODELS, THERMOCYCLER_MODULE_MODELS, + FLEX_SINGLE_SLOT_BY_CUTOUT_ID, + THERMOCYCLER_V2_FRONT_FIXTURE, } from '@opentrons/shared-data' +import { InProgressModal } from '../../molecules/InProgressModal/InProgressModal' import { GenericWizardTile } from '../../molecules/GenericWizardTile' import { LEFT_SLOTS } from './constants' +import type { DeckConfiguration, CreateCommand } from '@opentrons/shared-data' import type { ModuleCalibrationWizardStepProps } from './types' -import { InProgressModal } from '../../molecules/InProgressModal/InProgressModal' +import type { AxiosError } from 'axios' +import type { UseMutateFunction } from 'react-query' +import type { + CreateMaintenanceRunData, + MaintenanceRun, +} from '@opentrons/api-client' interface PlaceAdapterProps extends ModuleCalibrationWizardStepProps { - slotName: string + deckConfig: DeckConfiguration setCreatedAdapterId: (adapterId: string) => void + createMaintenanceRun: UseMutateFunction< + MaintenanceRun, + AxiosError, + CreateMaintenanceRunData, + unknown + > + isCreateLoading: boolean + createdMaintenanceRunId: string | null } export const BODY_STYLE = css` @@ -50,16 +66,33 @@ export const PlaceAdapter = (props: PlaceAdapterProps): JSX.Element | null => { const { proceed, goBack, + deckConfig, attachedModule, - slotName, chainRunCommands, setErrorMessage, setCreatedAdapterId, attachedPipette, isRobotMoving, + maintenanceRunId, + createMaintenanceRun, + isCreateLoading, + createdMaintenanceRunId, } = props const { t } = useTranslation('module_wizard_flows') + React.useEffect(() => { + if (createdMaintenanceRunId == null) { + createMaintenanceRun({}) + } + }, []) const mount = attachedPipette.mount + const cutoutId = deckConfig.find( + cc => + cc.opentronsModuleSerialNumber === attachedModule.serialNumber && + (attachedModule.moduleType !== THERMOCYCLER_MODULE_TYPE || + cc.cutoutFixtureId === THERMOCYCLER_V2_FRONT_FIXTURE) + )?.cutoutId + const slotName = + cutoutId != null ? FLEX_SINGLE_SLOT_BY_CUTOUT_ID[cutoutId] : null const handleOnClick = (): void => { const calibrationAdapterLoadName = getCalibrationAdapterLoadName( attachedModule.moduleModel @@ -70,15 +103,19 @@ export const PlaceAdapter = (props: PlaceAdapterProps): JSX.Element | null => { ) return } + if (slotName == null) { + console.error( + `could not load module ${attachedModule.moduleModel} into location ${slotName}` + ) + return + } const calibrationAdapterId = uuidv4() const commands: CreateCommand[] = [ { commandType: 'loadModule', params: { - location: { - slotName: slotName, - }, + location: { slotName }, model: attachedModule.moduleModel, moduleId: attachedModule.id, }, @@ -97,15 +134,21 @@ export const PlaceAdapter = (props: PlaceAdapterProps): JSX.Element | null => { { commandType: 'calibration/moveToMaintenancePosition', params: { - mount: mount, + mount, maintenancePosition: 'attachInstrument', }, }, ] chainRunCommands?.(commands, false) - .then(() => setCreatedAdapterId(calibrationAdapterId)) - .then(() => proceed()) - .catch((e: Error) => setErrorMessage(e.message)) + .then(() => { + setCreatedAdapterId(calibrationAdapterId) + }) + .then(() => { + proceed() + }) + .catch((e: Error) => { + setErrorMessage(e.message) + }) } const moduleType = attachedModule.moduleType @@ -188,6 +231,7 @@ export const PlaceAdapter = (props: PlaceAdapterProps): JSX.Element | null => { bodyText={bodyText} proceedButtonText={t('confirm_placement')} proceed={handleOnClick} + proceedIsDisabled={isCreateLoading || maintenanceRunId == null} back={goBack} /> ) diff --git a/app/src/organisms/ModuleWizardFlows/SelectLocation.tsx b/app/src/organisms/ModuleWizardFlows/SelectLocation.tsx index 6a694959079..2c78ecfb26b 100644 --- a/app/src/organisms/ModuleWizardFlows/SelectLocation.tsx +++ b/app/src/organisms/ModuleWizardFlows/SelectLocation.tsx @@ -1,15 +1,23 @@ import * as React from 'react' +import isEqual from 'lodash/isEqual' import { useTranslation } from 'react-i18next' import { css } from 'styled-components' +import { useUpdateDeckConfigurationMutation } from '@opentrons/react-api-client' import { - FLEX_ROBOT_TYPE, - getDeckDefFromRobotType, getModuleDisplayName, - THERMOCYCLER_MODULE_TYPE, - CutoutConfig, + getDeckDefFromRobotType, + FLEX_ROBOT_TYPE, + getCutoutFixturesForModuleModel, + SINGLE_CENTER_SLOT_FIXTURE, + SINGLE_CENTER_CUTOUTS, + SINGLE_LEFT_SLOT_FIXTURE, + SINGLE_RIGHT_CUTOUTS, + SINGLE_RIGHT_SLOT_FIXTURE, + getFixtureIdByCutoutIdFromModuleAnchorCutoutId, + SINGLE_SLOT_FIXTURES, } from '@opentrons/shared-data' import { - DeckLocationSelect, + DeckConfigurator, RESPONSIVENESS, SIZE_1, SPACING, @@ -19,6 +27,12 @@ import { import { Banner } from '../../atoms/Banner' import { GenericWizardTile } from '../../molecules/GenericWizardTile' import type { ModuleCalibrationWizardStepProps } from './types' +import type { + CutoutConfig, + DeckConfiguration, + CutoutFixtureId, + CutoutId, +} from '@opentrons/shared-data' export const BODY_STYLE = css` ${TYPOGRAPHY.pRegular}; @@ -29,9 +43,10 @@ export const BODY_STYLE = css` } ` interface SelectLocationProps extends ModuleCalibrationWizardStepProps { - setSlotName: React.Dispatch> availableSlotNames: string[] occupiedCutouts: CutoutConfig[] + deckConfig: DeckConfiguration + configuredFixtureIdByCutoutId: { [cutoutId in CutoutId]?: CutoutFixtureId } } export const SelectLocation = ( props: SelectLocationProps @@ -39,17 +54,19 @@ export const SelectLocation = ( const { proceed, attachedModule, - slotName, - setSlotName, - availableSlotNames, - occupiedCutouts, + deckConfig, + configuredFixtureIdByCutoutId, } = props const { t } = useTranslation('module_wizard_flows') const moduleName = getModuleDisplayName(attachedModule.moduleModel) const handleOnClick = (): void => { proceed() } + const { updateDeckConfiguration } = useUpdateDeckConfigurationMutation() const deckDef = getDeckDefFromRobotType(FLEX_ROBOT_TYPE) + const cutoutConfig = deckConfig.find( + cc => cc.opentronsModuleSerialNumber === attachedModule.serialNumber + ) const bodyText = ( <> @@ -61,28 +78,118 @@ export const SelectLocation = ( ) + const moduleFixtures = getCutoutFixturesForModuleModel( + attachedModule.moduleModel, + deckDef + ) + const mayMountToCutoutIds = moduleFixtures.reduce( + (acc, { mayMountTo }) => [...acc, ...mayMountTo], + [] + ) + const editableCutoutIds = deckConfig.reduce( + (acc, { cutoutId, cutoutFixtureId, opentronsModuleSerialNumber }) => { + const isCurrentConfiguration = + Object.values(configuredFixtureIdByCutoutId).includes( + cutoutFixtureId + ) && attachedModule.serialNumber === opentronsModuleSerialNumber + if ( + mayMountToCutoutIds.includes(cutoutId) && + (isCurrentConfiguration || + SINGLE_SLOT_FIXTURES.includes(cutoutFixtureId)) + ) { + return [...acc, cutoutId] + } + return acc + }, + [] + ) + + const handleAddFixture = (anchorCutoutId: CutoutId): void => { + const selectedFixtureIdByCutoutIds = getFixtureIdByCutoutIdFromModuleAnchorCutoutId( + anchorCutoutId, + moduleFixtures + ) + if (!isEqual(selectedFixtureIdByCutoutIds, configuredFixtureIdByCutoutId)) { + updateDeckConfiguration( + deckConfig.map(cc => { + if (cc.cutoutId in configuredFixtureIdByCutoutId) { + let replacementFixtureId: CutoutFixtureId = SINGLE_LEFT_SLOT_FIXTURE + if (SINGLE_CENTER_CUTOUTS.includes(cc.cutoutId)) { + replacementFixtureId = SINGLE_CENTER_SLOT_FIXTURE + } else if (SINGLE_RIGHT_CUTOUTS.includes(cc.cutoutId)) { + replacementFixtureId = SINGLE_RIGHT_SLOT_FIXTURE + } + return { + ...cc, + cutoutFixtureId: replacementFixtureId, + opentronsModuleSerialNumber: undefined, + } + } else if (cc.cutoutId in selectedFixtureIdByCutoutIds) { + return { + ...cc, + cutoutFixtureId: + selectedFixtureIdByCutoutIds[cc.cutoutId] ?? cc.cutoutFixtureId, + opentronsModuleSerialNumber: attachedModule.serialNumber, + } + } else { + return cc + } + }) + ) + } + } + + const handleRemoveFixture = (anchorCutoutId: CutoutId): void => { + const removedFixtureIdByCutoutIds = getFixtureIdByCutoutIdFromModuleAnchorCutoutId( + anchorCutoutId, + moduleFixtures + ) + updateDeckConfiguration( + deckConfig.map(cc => { + if (cc.cutoutId in removedFixtureIdByCutoutIds) { + let replacementFixtureId: CutoutFixtureId = SINGLE_LEFT_SLOT_FIXTURE + if (SINGLE_CENTER_CUTOUTS.includes(cc.cutoutId)) { + replacementFixtureId = SINGLE_CENTER_SLOT_FIXTURE + } else if (SINGLE_RIGHT_CUTOUTS.includes(cc.cutoutId)) { + replacementFixtureId = SINGLE_RIGHT_SLOT_FIXTURE + } + return { + ...cc, + cutoutFixtureId: replacementFixtureId, + opentronsModuleSerialNumber: undefined, + } + } else { + return cc + } + }) + ) + } + return ( setSlotName(loc.slotName)} - availableSlotNames={availableSlotNames} - occupiedCutouts={occupiedCutouts} - isThermocycler={ - attachedModule.moduleType === THERMOCYCLER_MODULE_TYPE + + Object.keys(configuredFixtureIdByCutoutId).includes(cutoutId) && + attachedModule.serialNumber === opentronsModuleSerialNumber + )?.cutoutId } - showTooltipOnDisabled={true} + height="250px" /> } bodyText={bodyText} proceedButtonText={t('confirm_location')} proceed={handleOnClick} - proceedIsDisabled={slotName == null} + proceedIsDisabled={cutoutConfig == null} disableProceedReason={ - slotName == null + cutoutConfig == null ? 'Current deck configuration prevents module placement' : undefined } diff --git a/app/src/organisms/ModuleWizardFlows/index.tsx b/app/src/organisms/ModuleWizardFlows/index.tsx index 39c235bd782..8c4bb1e8e97 100644 --- a/app/src/organisms/ModuleWizardFlows/index.tsx +++ b/app/src/organisms/ModuleWizardFlows/index.tsx @@ -2,17 +2,17 @@ import * as React from 'react' import { createPortal } from 'react-dom' import { useSelector } from 'react-redux' import { Trans, useTranslation } from 'react-i18next' -import { - useDeleteMaintenanceRunMutation, - useCurrentMaintenanceRun, - useDeckConfigurationQuery, -} from '@opentrons/react-api-client' +import { useDeleteMaintenanceRunMutation } from '@opentrons/react-api-client' import { COLORS, StyledText } from '@opentrons/components' import { getModuleType, getModuleDisplayName, FLEX_CUTOUT_BY_SLOT_ID, SINGLE_SLOT_FIXTURES, + getFixtureIdByCutoutIdFromModuleSlotName, + getCutoutFixturesForModuleModel, + getDeckDefFromRobotType, + FLEX_ROBOT_TYPE, } from '@opentrons/shared-data' import { LegacyModalShell } from '../../molecules/LegacyModal' import { getTopPortalEl } from '../../App/portal' @@ -33,6 +33,8 @@ import { PlaceAdapter } from './PlaceAdapter' import { SelectLocation } from './SelectLocation' import { Success } from './Success' import { DetachProbe } from './DetachProbe' +import { useNotifyDeckConfigurationQuery } from '../../resources/deck_configuration' +import { useNotifyCurrentMaintenanceRun } from '../../resources/maintenance_runs' import type { AttachedModule, CommandData } from '@opentrons/api-client' import type { @@ -45,7 +47,6 @@ interface ModuleWizardFlowsProps { attachedModule: AttachedModule closeFlow: () => void isPrepCommandLoading: boolean - initialSlotName?: string onComplete?: () => void prepCommandErrorMessage?: string } @@ -57,7 +58,6 @@ export const ModuleWizardFlows = ( ): JSX.Element | null => { const { attachedModule, - initialSlotName, isPrepCommandLoading, closeFlow, onComplete, @@ -72,12 +72,25 @@ export const ModuleWizardFlows = ( : attachedPipettes.right const moduleCalibrationSteps = getModuleCalibrationSteps() - const deckConfig = useDeckConfigurationQuery().data ?? [] + const deckDef = getDeckDefFromRobotType(FLEX_ROBOT_TYPE) + const deckConfig = useNotifyDeckConfigurationQuery().data ?? [] + const moduleCutoutConfig = deckConfig.find( + cc => cc.opentronsModuleSerialNumber === attachedModule.serialNumber + ) + // mapping of cutoutId's occupied by the target module and their cutoutFixtureId's per cutout + const fixtureIdByCutoutId = + moduleCutoutConfig != null + ? getFixtureIdByCutoutIdFromModuleSlotName( + moduleCutoutConfig.cutoutId.replace('cutout', ''), + getCutoutFixturesForModuleModel(attachedModule.moduleModel, deckDef), + deckDef + ) + : {} const occupiedCutouts = deckConfig.filter( - (fixture: CutoutConfig) => + (cutoutConfig: CutoutConfig) => !SINGLE_SLOT_FIXTURES.includes( - fixture.cutoutFixtureId as SingleSlotCutoutFixtureId - ) + cutoutConfig.cutoutFixtureId as SingleSlotCutoutFixtureId + ) && !Object.keys(fixtureIdByCutoutId).includes(cutoutConfig.cutoutId) ) const availableSlotNames = FLEX_SLOT_NAMES_BY_MOD_TYPE[ @@ -90,9 +103,6 @@ export const ModuleWizardFlows = ( ) ) ?? [] - const [slotName, setSlotName] = React.useState( - initialSlotName != null ? initialSlotName : availableSlotNames?.[0] ?? null - ) const [currentStepIndex, setCurrentStepIndex] = React.useState(0) const totalStepCount = moduleCalibrationSteps.length - 1 const currentStep = moduleCalibrationSteps?.[currentStepIndex] @@ -115,7 +125,7 @@ export const ModuleWizardFlows = ( setMonitorMaintenanceRunForDeletion, ] = React.useState(false) - const { data: maintenanceRunData } = useCurrentMaintenanceRun({ + const { data: maintenanceRunData } = useNotifyCurrentMaintenanceRun({ refetchInterval: RUN_REFETCH_INTERVAL, enabled: createdMaintenanceRunId != null, }) @@ -247,7 +257,6 @@ export const ModuleWizardFlows = ( errorMessage, isOnDevice, attachedModule, - slotName, isExiting, } @@ -276,7 +285,7 @@ export const ModuleWizardFlows = ( ) : ( , @@ -289,23 +298,16 @@ export const ModuleWizardFlows = ( } else if (isExiting) { modalContent = } else if (currentStep.section === SECTIONS.BEFORE_BEGINNING) { - modalContent = ( - - ) + modalContent = } else if (currentStep.section === SECTIONS.SELECT_LOCATION) { modalContent = ( ) } else if (currentStep.section === SECTIONS.PLACE_ADAPTER) { @@ -313,7 +315,11 @@ export const ModuleWizardFlows = ( ) } else if (currentStep.section === SECTIONS.ATTACH_PROBE) { @@ -321,7 +327,9 @@ export const ModuleWizardFlows = ( ) } else if (currentStep.section === SECTIONS.DETACH_PROBE) { diff --git a/app/src/organisms/ModuleWizardFlows/types.ts b/app/src/organisms/ModuleWizardFlows/types.ts index f2b2764b12c..df6020e9b36 100644 --- a/app/src/organisms/ModuleWizardFlows/types.ts +++ b/app/src/organisms/ModuleWizardFlows/types.ts @@ -24,7 +24,6 @@ export interface ModuleCalibrationWizardStepProps { attachedPipette: PipetteInformation errorMessage: string | null setErrorMessage: (message: string | null) => void - slotName: string isOnDevice: boolean | null } diff --git a/app/src/organisms/NetworkSettings/AlternativeSecurityTypeModal.tsx b/app/src/organisms/NetworkSettings/AlternativeSecurityTypeModal.tsx index b0e365d08fc..375476f2a2e 100644 --- a/app/src/organisms/NetworkSettings/AlternativeSecurityTypeModal.tsx +++ b/app/src/organisms/NetworkSettings/AlternativeSecurityTypeModal.tsx @@ -26,7 +26,7 @@ interface AlternativeSecurityTypeModalProps { export function AlternativeSecurityTypeModal({ setShowAlternativeSecurityTypeModal, }: AlternativeSecurityTypeModalProps): JSX.Element { - const { t } = useTranslation('device_settings') + const { t } = useTranslation(['device_settings', 'branded']) const history = useHistory() const modalHeader: ModalHeaderBaseProps = { title: t('alternative_security_types'), @@ -58,7 +58,7 @@ export function AlternativeSecurityTypeModal({ fontWeight={TYPOGRAPHY.fontWeightRegular} color={COLORS.grey60} > - {t('alternative_security_types_description')} + {t('branded:alternative_security_types_description')} 0 + : false + const handleCardClick = (): void => { setShowSpinner(true) - cloneRun() - trackEvent({ - name: 'proceedToRun', - properties: { sourceLocation: 'RecentRunProtocolCard' }, - }) + if (hasRunTimeParameters) { + history.push(`/protocols/${protocolId}`) + } else { + cloneRun() + trackEvent({ + name: ANALYTICS_PROTOCOL_PROCEED_TO_RUN, + properties: { sourceLocation: 'RecentRunProtocolCard' }, + }) + } // TODO(BC, 08/29/23): reintroduce this analytics event when we refactor the hook to fetch data lazily (performance concern) // trackProtocolRunEvent({ name: 'runAgain' }) } diff --git a/app/src/organisms/OnDeviceDisplay/RobotDashboard/__tests__/RecentRunProtocolCard.test.tsx b/app/src/organisms/OnDeviceDisplay/RobotDashboard/__tests__/RecentRunProtocolCard.test.tsx index 1584e3ce723..fc2f21a3034 100644 --- a/app/src/organisms/OnDeviceDisplay/RobotDashboard/__tests__/RecentRunProtocolCard.test.tsx +++ b/app/src/organisms/OnDeviceDisplay/RobotDashboard/__tests__/RecentRunProtocolCard.test.tsx @@ -5,8 +5,14 @@ import { MemoryRouter } from 'react-router-dom' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { when } from 'vitest-when' -import { useProtocolQuery } from '@opentrons/react-api-client' -import { RUN_STATUS_FAILED } from '@opentrons/api-client' +import { + useProtocolQuery, + useProtocolAnalysisAsDocumentQuery, +} from '@opentrons/react-api-client' +import { + RUN_STATUS_FAILED, + simpleAnalysisFileFixture, +} from '@opentrons/api-client' import { COLORS } from '@opentrons/components' import { renderWithProviders } from '../../../../__testing-utils__' @@ -14,7 +20,10 @@ import { i18n } from '../../../../i18n' import { Skeleton } from '../../../../atoms/Skeleton' import { useMissingProtocolHardware } from '../../../../pages/Protocols/hooks' import { useTrackProtocolRunEvent } from '../../../Devices/hooks' -import { useTrackEvent } from '../../../../redux/analytics' +import { + useTrackEvent, + ANALYTICS_PROTOCOL_PROCEED_TO_RUN, +} from '../../../../redux/analytics' import { useCloneRun } from '../../../ProtocolUpload/hooks' import { useRerunnableStatusText } from '../hooks' import { RecentRunProtocolCard } from '../' @@ -24,11 +33,23 @@ import { INIT_STATUS, } from '../../../../resources/health/hooks' +import type { useHistory } from 'react-router-dom' import type { ProtocolHardware } from '../../../../pages/Protocols/hooks' +const mockPush = vi.fn() + +vi.mock('react-router-dom', async importOriginal => { + const actual = await importOriginal() + return { + ...actual, + useHistory: () => ({ push: mockPush } as any), + } +}) + vi.mock('@opentrons/react-api-client') vi.mock('../../../../atoms/Skeleton') vi.mock('../../../../pages/Protocols/hooks') +vi.mock('../../../../pages/ProtocolDetails') vi.mock('../../../../organisms/Devices/hooks') vi.mock('../../../../organisms/RunTimeControl/hooks') vi.mock('../../../../organisms/ProtocolUpload/hooks') @@ -128,7 +149,18 @@ describe('RecentRunProtocolCard', () => { data: { data: [mockRunData] }, } as any) vi.mocked(useProtocolQuery).mockReturnValue({ - data: { data: { metadata: { protocolName: 'mockProtocol' } } }, + data: { + data: { + metadata: { protocolName: 'mockProtocol' }, + id: 'mockProtocolId', + }, + }, + } as any) + vi.mocked(useProtocolAnalysisAsDocumentQuery).mockReturnValue({ + data: { + ...simpleAnalysisFileFixture, + runTimeParameters: [], + }, } as any) vi.mocked(useRobotInitializationStatus).mockReturnValue( INIT_STATUS.SUCCEEDED @@ -218,10 +250,10 @@ describe('RecentRunProtocolCard', () => { it('when tapping a card, mock functions is called and loading state is activated', () => { render(props) const button = screen.getByLabelText('RecentRunProtocolCard') - expect(button).toHaveStyle(`background-color: ${COLORS.green40}`) + expect(button).toHaveStyle(`background-color: ${COLORS.green35}`) fireEvent.click(button) expect(mockTrackEvent).toHaveBeenCalledWith({ - name: 'proceedToRun', + name: ANALYTICS_PROTOCOL_PROCEED_TO_RUN, properties: { sourceLocation: 'RecentRunProtocolCard' }, }) // TODO(BC, 08/30/23): reintroduce check for tracking when tracking is reintroduced lazily @@ -252,4 +284,14 @@ describe('RecentRunProtocolCard', () => { const [{ getByText }] = render(props) getByText('mock Skeleton') }) + + it('should push to protocol details if protocol contains runtime parameters', () => { + vi.mocked(useProtocolAnalysisAsDocumentQuery).mockReturnValue({ + data: simpleAnalysisFileFixture, + } as any) + render(props) + const button = screen.getByLabelText('RecentRunProtocolCard') + fireEvent.click(button) + expect(mockPush).toBeCalledWith('/protocols/mockProtocolId') + }) }) diff --git a/app/src/organisms/OnDeviceDisplay/RobotDashboard/__tests__/RecentRunProtocolCarousel.test.tsx b/app/src/organisms/OnDeviceDisplay/RobotDashboard/__tests__/RecentRunProtocolCarousel.test.tsx index 85e956ed977..8bc3a481843 100644 --- a/app/src/organisms/OnDeviceDisplay/RobotDashboard/__tests__/RecentRunProtocolCarousel.test.tsx +++ b/app/src/organisms/OnDeviceDisplay/RobotDashboard/__tests__/RecentRunProtocolCarousel.test.tsx @@ -26,6 +26,7 @@ const mockRun = { pipettes: [], protocolId: 'mockSortedProtocolID', status: 'stopped', + runTimeParameters: [], } const render = ( diff --git a/app/src/organisms/OnDeviceDisplay/RunningProtocol/ConfirmCancelRunModal.tsx b/app/src/organisms/OnDeviceDisplay/RunningProtocol/ConfirmCancelRunModal.tsx index c2841101133..7aaf9007c1a 100644 --- a/app/src/organisms/OnDeviceDisplay/RunningProtocol/ConfirmCancelRunModal.tsx +++ b/app/src/organisms/OnDeviceDisplay/RunningProtocol/ConfirmCancelRunModal.tsx @@ -21,7 +21,7 @@ import { SmallButton } from '../../../atoms/buttons' import { Modal } from '../../../molecules/Modal' import { useTrackProtocolRunEvent } from '../../../organisms/Devices/hooks' import { useRunStatus } from '../../../organisms/RunTimeControl/hooks' -import { ANALYTICS_PROTOCOL_RUN_CANCEL } from '../../../redux/analytics' +import { ANALYTICS_PROTOCOL_RUN_ACTION } from '../../../redux/analytics' import { getLocalRobot } from '../../../redux/discovery' import { CancelingRunModal } from './CancelingRunModal' @@ -71,7 +71,7 @@ export function ConfirmCancelRunModal({ React.useEffect(() => { if (runStatus === RUN_STATUS_STOPPED) { - trackProtocolRunEvent({ name: ANALYTICS_PROTOCOL_RUN_CANCEL }) + trackProtocolRunEvent({ name: ANALYTICS_PROTOCOL_RUN_ACTION.CANCEL }) dismissCurrentRun(runId) if (!isActiveRun) { if (protocolId != null) { @@ -98,7 +98,7 @@ export function ConfirmCancelRunModal({ paddingBottom={SPACING.spacing32} paddingTop={`${isActiveRun ? SPACING.spacing32 : '0'}`} > - {t('cancel_run_alert_info')} + {t('cancel_run_alert_info_flex')} {t('cancel_run_module_info')}
void protocolName?: string currentRunCommandIndex?: number @@ -138,13 +135,15 @@ export function CurrentRunningProtocolCommand({ robotType, protocolName, currentRunCommandIndex, + lastRunCommand, lastAnimatedCommand, updateLastAnimatedCommand, }: CurrentRunningProtocolCommandProps): JSX.Element | null { const { t } = useTranslation('run_details') - const currentCommand = robotSideAnalysis?.commands.find( - (c: RunTimeCommand, index: number) => index === currentRunCommandIndex - ) + const currentCommand = + robotSideAnalysis?.commands.find( + (c: RunTimeCommand, index: number) => index === currentRunCommandIndex + ) ?? lastRunCommand let shouldAnimate = true if (currentCommand?.key != null) { @@ -168,14 +167,14 @@ export function CurrentRunningProtocolCommand({ const onTogglePlayPause = (): void => { if (runStatus === RUN_STATUS_RUNNING) { pauseRun() - trackProtocolRunEvent({ name: ANALYTICS_PROTOCOL_RUN_PAUSE }) + trackProtocolRunEvent({ name: ANALYTICS_PROTOCOL_RUN_ACTION.PAUSE }) } else { playRun() trackProtocolRunEvent({ name: runStatus === RUN_STATUS_IDLE - ? ANALYTICS_PROTOCOL_RUN_START - : ANALYTICS_PROTOCOL_RUN_RESUME, + ? ANALYTICS_PROTOCOL_RUN_ACTION.START + : ANALYTICS_PROTOCOL_RUN_ACTION.RESUME, properties: runStatus === RUN_STATUS_IDLE && robotAnalyticsData != null ? robotAnalyticsData diff --git a/app/src/organisms/OnDeviceDisplay/RunningProtocol/RunFailedModal.tsx b/app/src/organisms/OnDeviceDisplay/RunningProtocol/RunFailedModal.tsx index 072180008da..3c60dd13074 100644 --- a/app/src/organisms/OnDeviceDisplay/RunningProtocol/RunFailedModal.tsx +++ b/app/src/organisms/OnDeviceDisplay/RunningProtocol/RunFailedModal.tsx @@ -33,7 +33,7 @@ export function RunFailedModal({ setShowRunFailedModal, errors, }: RunFailedModalProps): JSX.Element | null { - const { t, i18n } = useTranslation(['run_details', 'shared']) + const { t, i18n } = useTranslation(['run_details', 'shared', 'branded']) const history = useHistory() const { stopRun } = useStopRunMutation() const [isCanceling, setIsCanceling] = React.useState(false) @@ -106,7 +106,7 @@ export function RunFailedModal({ word-break: break-word; `} > - {t('contact_information')} + {t('branded:contact_information')} void + errorType?: string + protocolName?: string +} + +export function RunPausedSplash({ + onClick, + errorType, + protocolName, +}: RunPausedSplashProps): JSX.Element { + const { t } = useTranslation('error_recovery') + + let subText: string | null + switch (errorType) { + default: + subText = protocolName ?? null + } + + return ( + + + + + {t('run_paused')} + + + {subText} + + + + ) +} + +const SplashHeader = styled.h1` + font-weight: ${TYPOGRAPHY.fontWeightBold}; + text-align: ${TYPOGRAPHY.textAlignLeft}; + font-size: ${TYPOGRAPHY.fontSize80}; + line-height: ${TYPOGRAPHY.lineHeight96}; + color: ${COLORS.white}; +` +const SplashBody = styled.h4` + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 4; + overflow: hidden; + overflow-wrap: ${OVERFLOW_WRAP_BREAK_WORD}; + font-weight: ${TYPOGRAPHY.fontWeightSemiBold}; + text-align: ${TYPOGRAPHY.textAlignCenter}; + text-transform: ${TYPOGRAPHY.textTransformCapitalize}; + font-size: ${TYPOGRAPHY.fontSize32}; + line-height: ${TYPOGRAPHY.lineHeight42}; + color: ${COLORS.white}; +` + +const SplashFrame = styled(Flex)` + width: 100%; + height: 100%; + flex-direction: ${DIRECTION_COLUMN}; + justify-content: ${JUSTIFY_CENTER}; + align-items: ${ALIGN_CENTER}; + grid-gap: ${SPACING.spacing40}; +` diff --git a/app/src/organisms/OnDeviceDisplay/RunningProtocol/RunningProtocolCommandList.tsx b/app/src/organisms/OnDeviceDisplay/RunningProtocol/RunningProtocolCommandList.tsx index 0c2f00ef2ea..c59fedd338f 100644 --- a/app/src/organisms/OnDeviceDisplay/RunningProtocol/RunningProtocolCommandList.tsx +++ b/app/src/organisms/OnDeviceDisplay/RunningProtocol/RunningProtocolCommandList.tsx @@ -25,11 +25,7 @@ import { CommandText } from '../../CommandText' import { CommandIcon } from '../../RunPreview/CommandIcon' import { PlayPauseButton } from './PlayPauseButton' import { StopButton } from './StopButton' -import { - ANALYTICS_PROTOCOL_RUN_START, - ANALYTICS_PROTOCOL_RUN_RESUME, - ANALYTICS_PROTOCOL_RUN_PAUSE, -} from '../../../redux/analytics' +import { ANALYTICS_PROTOCOL_RUN_ACTION } from '../../../redux/analytics' import type { CompletedProtocolAnalysis, @@ -119,14 +115,14 @@ export function RunningProtocolCommandList({ const onTogglePlayPause = (): void => { if (runStatus === RUN_STATUS_RUNNING) { pauseRun() - trackProtocolRunEvent({ name: ANALYTICS_PROTOCOL_RUN_PAUSE }) + trackProtocolRunEvent({ name: ANALYTICS_PROTOCOL_RUN_ACTION.PAUSE }) } else { playRun() trackProtocolRunEvent({ name: runStatus === RUN_STATUS_IDLE - ? ANALYTICS_PROTOCOL_RUN_START - : ANALYTICS_PROTOCOL_RUN_RESUME, + ? ANALYTICS_PROTOCOL_RUN_ACTION.START + : ANALYTICS_PROTOCOL_RUN_ACTION.RESUME, properties: runStatus === RUN_STATUS_IDLE && robotAnalyticsData != null ? robotAnalyticsData diff --git a/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/ConfirmCancelRunModal.test.tsx b/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/ConfirmCancelRunModal.test.tsx index fad8b4b8de1..36e23a35df6 100644 --- a/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/ConfirmCancelRunModal.test.tsx +++ b/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/ConfirmCancelRunModal.test.tsx @@ -97,12 +97,10 @@ describe('ConfirmCancelRunModal', () => { vi.restoreAllMocks() }) - it('should render text and buttons', () => { + it('should render correct text and buttons', () => { render(props) - screen.getByText('Are you sure you want to cancel this run?') - screen.getByText( - 'Doing so will terminate this run, drop any attached tips in the trash container and home your robot.' - ) + screen.getByText('Are you sure you want to cancel?') + screen.getByText('Doing so will terminate this run and home your robot.') screen.getByText( 'Additionally, any hardware modules used within the protocol will remain active and maintain their current states until deactivated.' ) @@ -111,7 +109,7 @@ describe('ConfirmCancelRunModal', () => { screen.getByText('Cancel run') }) - it('shoudler render the canceling run modal when run is dismissing', () => { + it('should render the canceling run modal when run is dismissing', () => { vi.mocked(useDismissCurrentRunMutation).mockReturnValue({ dismissCurrentRun: mockDismissCurrentRun, isLoading: true, diff --git a/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/CurrentRunningProtocolCommand.test.tsx b/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/CurrentRunningProtocolCommand.test.tsx index edb7bc99b10..92b5e7aa274 100644 --- a/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/CurrentRunningProtocolCommand.test.tsx +++ b/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/CurrentRunningProtocolCommand.test.tsx @@ -46,6 +46,7 @@ describe('CurrentRunningProtocolCommand', () => { protocolName: 'mockRunningProtocolName', currentRunCommandIndex: 0, lastAnimatedCommand: null, + lastRunCommand: null, updateLastAnimatedCommand: mockUpdateLastAnimatedCommand, robotType: FLEX_ROBOT_TYPE, } diff --git a/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/RunPausedSplash.test.tsx b/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/RunPausedSplash.test.tsx new file mode 100644 index 00000000000..0f7455c154f --- /dev/null +++ b/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/RunPausedSplash.test.tsx @@ -0,0 +1,51 @@ +import * as React from 'react' +import { MemoryRouter } from 'react-router-dom' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import { fireEvent, screen } from '@testing-library/react' +import { renderWithProviders } from '../../../../__testing-utils__' +import { i18n } from '../../../../i18n' + +import { COLORS } from '@opentrons/components' + +import { RunPausedSplash } from '../RunPausedSplash' + +const render = (props: React.ComponentProps) => { + return renderWithProviders( + + + , + { + i18nInstance: i18n, + } + ) +} + +const MOCK_PROTOCOL_NAME = 'MOCK_PROTOCOL' + +describe('ConfirmCancelRunModal', () => { + let props: React.ComponentProps + const mockOnClose = vi.fn() + + beforeEach(() => { + props = { + onClick: mockOnClose, + protocolName: MOCK_PROTOCOL_NAME, + errorType: '', + } + }) + + afterEach(() => { + vi.restoreAllMocks() + }) + + it('should render a generic paused screen if there is no errorType', () => { + render(props) + expect(screen.getByText('Run paused')).toBeInTheDocument() + expect(screen.getByText(MOCK_PROTOCOL_NAME)) + expect(screen.getByRole('button')).toHaveStyle({ + 'background-color': COLORS.grey50, + }) + fireEvent.click(screen.getByRole('button')) + expect(mockOnClose).toHaveBeenCalled() + }) +}) diff --git a/app/src/organisms/PipetteWizardFlows/AttachProbe.tsx b/app/src/organisms/PipetteWizardFlows/AttachProbe.tsx index 74e910758f7..489269e4311 100644 --- a/app/src/organisms/PipetteWizardFlows/AttachProbe.tsx +++ b/app/src/organisms/PipetteWizardFlows/AttachProbe.tsx @@ -15,7 +15,6 @@ import { WASTE_CHUTE_CUTOUT, CreateCommand, } from '@opentrons/shared-data' -import { useDeckConfigurationQuery } from '@opentrons/react-api-client' import { Banner } from '../../atoms/Banner' import { GenericWizardTile } from '../../molecules/GenericWizardTile' import { SimpleWizardBody } from '../../molecules/SimpleWizardBody' @@ -26,6 +25,8 @@ import probing96 from '../../assets/videos/pipette-wizard-flows/Pipette_Probing_ import { BODY_STYLE, SECTIONS, FLOWS } from './constants' import { getPipetteAnimations } from './utils' import { ProbeNotAttached } from './ProbeNotAttached' +import { useNotifyDeckConfigurationQuery } from '../../resources/deck_configuration' + import type { PipetteWizardStepProps } from './types' interface AttachProbeProps extends PipetteWizardStepProps { @@ -69,7 +70,7 @@ export const AttachProbe = (props: AttachProbeProps): JSX.Element | null => { const is96Channel = attachedPipettes[mount]?.data.channels === 96 const calSlotNum = 'C2' const axes: MotorAxes = mount === LEFT ? ['leftZ'] : ['rightZ'] - const deckConfig = useDeckConfigurationQuery().data + const deckConfig = useNotifyDeckConfigurationQuery().data const isWasteChuteOnDeck = deckConfig?.find(fixture => fixture.cutoutId === WASTE_CHUTE_CUTOUT) ?? false @@ -79,7 +80,11 @@ export const AttachProbe = (props: AttachProbeProps): JSX.Element | null => { const verifyCommands: CreateCommand[] = [ { commandType: 'verifyTipPresence', - params: { pipetteId: pipetteId, expectedState: 'present' }, + params: { + pipetteId: pipetteId, + expectedState: 'present', + followSingularSensor: 'primary', + }, }, ] const homeCommands: CreateCommand[] = [ diff --git a/app/src/organisms/PipetteWizardFlows/BeforeBeginning.tsx b/app/src/organisms/PipetteWizardFlows/BeforeBeginning.tsx index b20b1bfe4e0..165c37053f9 100644 --- a/app/src/organisms/PipetteWizardFlows/BeforeBeginning.tsx +++ b/app/src/organisms/PipetteWizardFlows/BeforeBeginning.tsx @@ -13,16 +13,14 @@ import { RIGHT, SINGLE_MOUNT_PIPETTES, WEIGHT_OF_96_CHANNEL, - LoadedPipette, - getPipetteNameSpecs, WASTE_CHUTE_CUTOUT, } from '@opentrons/shared-data' -import { useDeckConfigurationQuery } from '@opentrons/react-api-client' import { Banner } from '../../atoms/Banner' import { SimpleWizardBody } from '../../molecules/SimpleWizardBody' import { GenericWizardTile } from '../../molecules/GenericWizardTile' import { InProgressModal } from '../../molecules/InProgressModal/InProgressModal' import { WizardRequiredEquipmentList } from '../../molecules/WizardRequiredEquipmentList' +import { usePipetteNameSpecs } from '../../resources/instruments/hooks' import { CALIBRATION_PROBE, FLOWS, @@ -33,8 +31,14 @@ import { BODY_STYLE, } from './constants' import { getIsGantryEmpty } from './utils' +import { useNotifyDeckConfigurationQuery } from '../../resources/deck_configuration' + import type { AxiosError } from 'axios' -import type { CreateCommand } from '@opentrons/shared-data' +import type { + CreateCommand, + LoadedPipette, + PipetteName, +} from '@opentrons/shared-data' import type { CreateMaintenanceRunData, MaintenanceRun, @@ -84,11 +88,15 @@ export const BeforeBeginning = ( isGantryEmpty && selectedPipette === NINETY_SIX_CHANNEL && flowType === FLOWS.ATTACH - const deckConfig = useDeckConfigurationQuery().data + const deckConfig = useNotifyDeckConfigurationQuery().data const isWasteChuteOnDeck = deckConfig?.find(fixture => fixture.cutoutId === WASTE_CHUTE_CUTOUT) ?? false + const pipetteDisplayName = usePipetteNameSpecs( + requiredPipette?.pipetteName as PipetteName + )?.displayName + if ( pipetteId == null && (flowType === FLOWS.CALIBRATE || flowType === FLOWS.DETACH) @@ -108,9 +116,7 @@ export const BeforeBeginning = ( bodyTranslationKey = 'remove_labware' let displayName: string | undefined if (requiredPipette != null) { - displayName = - getPipetteNameSpecs(requiredPipette.pipetteName)?.displayName ?? - requiredPipette.pipetteName + displayName = pipetteDisplayName ?? requiredPipette.pipetteName } if (selectedPipette === SINGLE_MOUNT_PIPETTES) { equipmentList = [ @@ -133,9 +139,7 @@ export const BeforeBeginning = ( } case FLOWS.DETACH: { if (requiredPipette != null) { - const displayName = - getPipetteNameSpecs(requiredPipette.pipetteName)?.displayName ?? - requiredPipette.pipetteName + const displayName = pipetteDisplayName ?? requiredPipette.pipetteName bodyTranslationKey = 'remove_labware' if (requiredPipette.pipetteName === 'p1000_96') { diff --git a/app/src/organisms/PipetteWizardFlows/ChoosePipette.tsx b/app/src/organisms/PipetteWizardFlows/ChoosePipette.tsx index 8d9330315c7..f3926a711a3 100644 --- a/app/src/organisms/PipetteWizardFlows/ChoosePipette.tsx +++ b/app/src/organisms/PipetteWizardFlows/ChoosePipette.tsx @@ -207,7 +207,11 @@ export const ChoosePipette = (props: ChoosePipetteProps): JSX.Element => {
) : ( - + {showExitConfirmation ? ( setShowExitConfirmation(false)} @@ -218,7 +222,7 @@ export const ChoosePipette = (props: ChoosePipetteProps): JSX.Element => { ) : ( diff --git a/app/src/organisms/PipetteWizardFlows/ProbeNotAttached.tsx b/app/src/organisms/PipetteWizardFlows/ProbeNotAttached.tsx index 1056cf9831b..b73111af420 100644 --- a/app/src/organisms/PipetteWizardFlows/ProbeNotAttached.tsx +++ b/app/src/organisms/PipetteWizardFlows/ProbeNotAttached.tsx @@ -26,14 +26,20 @@ interface ProbeNotAttachedProps { export const ProbeNotAttached = ( props: ProbeNotAttachedProps ): JSX.Element | null => { - const { t, i18n } = useTranslation(['pipette_wizard_flows', 'shared']) + const { t, i18n } = useTranslation([ + 'pipette_wizard_flows', + 'shared', + 'branded', + ]) const { isOnDevice, handleOnClick, setShowUnableToDetect } = props const [numberOfTryAgains, setNumberOfTryAgains] = React.useState(0) return ( 2 ? t('something_seems_wrong') : undefined} + subHeader={ + numberOfTryAgains > 2 ? t('branded:something_seems_wrong') : undefined + } iconColor={COLORS.red50} isSuccess={false} > diff --git a/app/src/organisms/PipetteWizardFlows/Results.tsx b/app/src/organisms/PipetteWizardFlows/Results.tsx index 04549e686df..5f652f3f895 100644 --- a/app/src/organisms/PipetteWizardFlows/Results.tsx +++ b/app/src/organisms/PipetteWizardFlows/Results.tsx @@ -12,19 +12,19 @@ import { StyledText, TYPOGRAPHY, } from '@opentrons/components' -import { - getPipetteNameSpecs, - LEFT, - RIGHT, - LoadedPipette, - MotorAxes, - NINETY_SIX_CHANNEL, -} from '@opentrons/shared-data' +import { LEFT, RIGHT, NINETY_SIX_CHANNEL } from '@opentrons/shared-data' +import { SmallButton } from '../../atoms/buttons' import { InProgressModal } from '../../molecules/InProgressModal/InProgressModal' import { SimpleWizardBody } from '../../molecules/SimpleWizardBody' -import { SmallButton } from '../../atoms/buttons' +import { usePipetteNameSpecs } from '../../resources/instruments/hooks' import { CheckPipetteButton } from './CheckPipetteButton' import { FLOWS } from './constants' + +import type { + LoadedPipette, + MotorAxes, + PipetteName, +} from '@opentrons/shared-data' import type { PipetteWizardStepProps } from './types' interface ResultsProps extends PipetteWizardStepProps { @@ -60,17 +60,22 @@ export const Results = (props: ResultsProps): JSX.Element => { setShowErrorMessage, nextMount, } = props - const { t, i18n } = useTranslation(['pipette_wizard_flows', 'shared']) + const { t, i18n } = useTranslation([ + 'pipette_wizard_flows', + 'shared', + 'branded', + ]) const pipetteName = attachedPipettes[mount] != null ? attachedPipettes[mount]?.displayName : '' const isCorrectPipette = requiredPipette != null && requiredPipette.pipetteName === attachedPipettes[mount]?.instrumentName + const requiredPipDisplayName = - requiredPipette != null - ? getPipetteNameSpecs(requiredPipette.pipetteName)?.displayName - : null + usePipetteNameSpecs(requiredPipette?.pipetteName as PipetteName) + ?.displayName ?? null + const [numberOfTryAgains, setNumberOfTryAgains] = React.useState(0) let header: string = 'unknown results screen' let iconColor: string = COLORS.green50 @@ -263,7 +268,8 @@ export const Results = (props: ResultsProps): JSX.Element => { } } ` - subHeader = numberOfTryAgains > 2 ? t('something_seems_wrong') : undefined + subHeader = + numberOfTryAgains > 2 ? t('branded:something_seems_wrong') : undefined button = ( <> {isOnDevice ? ( diff --git a/app/src/organisms/PipetteWizardFlows/__tests__/AttachProbe.test.tsx b/app/src/organisms/PipetteWizardFlows/__tests__/AttachProbe.test.tsx index 3043558a5da..2ec224707b9 100644 --- a/app/src/organisms/PipetteWizardFlows/__tests__/AttachProbe.test.tsx +++ b/app/src/organisms/PipetteWizardFlows/__tests__/AttachProbe.test.tsx @@ -2,7 +2,6 @@ import * as React from 'react' import { fireEvent, screen, waitFor } from '@testing-library/react' import { describe, it, beforeEach, vi, expect } from 'vitest' -import { useDeckConfigurationQuery } from '@opentrons/react-api-client' import { LEFT, SINGLE_MOUNT_PIPETTES } from '@opentrons/shared-data' import { @@ -18,13 +17,14 @@ import { import { RUN_ID_1 } from '../../RunTimeControl/__fixtures__' import { FLOWS } from '../constants' import { AttachProbe } from '../AttachProbe' +import { useNotifyDeckConfigurationQuery } from '../../../resources/deck_configuration' const render = (props: React.ComponentProps) => { return renderWithProviders(, { i18nInstance: i18n, })[0] } -vi.mock('@opentrons/react-api-client') +vi.mock('../../../resources/deck_configuration') describe('AttachProbe', () => { let props: React.ComponentProps @@ -47,7 +47,7 @@ describe('AttachProbe', () => { selectedPipette: SINGLE_MOUNT_PIPETTES, isOnDevice: false, } - vi.mocked(useDeckConfigurationQuery).mockReturnValue({ + vi.mocked(useNotifyDeckConfigurationQuery).mockReturnValue({ data: [ { cutoutId: 'cutoutD3', @@ -71,7 +71,11 @@ describe('AttachProbe', () => { [ { commandType: 'verifyTipPresence', - params: { pipetteId: 'abc', expectedState: 'present' }, + params: { + pipetteId: 'abc', + expectedState: 'present', + followSingularSensor: 'primary', + }, }, ], false @@ -205,7 +209,11 @@ describe('AttachProbe', () => { [ { commandType: 'verifyTipPresence', - params: { pipetteId: 'abc', expectedState: 'present' }, + params: { + pipetteId: 'abc', + expectedState: 'present', + followSingularSensor: 'primary', + }, }, ], false diff --git a/app/src/organisms/PipetteWizardFlows/__tests__/ChoosePipette.test.tsx b/app/src/organisms/PipetteWizardFlows/__tests__/ChoosePipette.test.tsx index 37570d8c5ff..11a0f0f8452 100644 --- a/app/src/organisms/PipetteWizardFlows/__tests__/ChoosePipette.test.tsx +++ b/app/src/organisms/PipetteWizardFlows/__tests__/ChoosePipette.test.tsx @@ -65,7 +65,7 @@ describe('ChoosePipette', () => { // Single and 8-Channel pipettes are selected first by default expect(singleMountPipettes).toHaveStyle( - `background-color: ${COLORS.blue30}` + `background-color: ${COLORS.blue10}` ) expect(ninetySixPipette).toHaveStyle(`background-color: ${COLORS.white}`) @@ -139,7 +139,7 @@ describe('ChoosePipette', () => { name: '96-Channel pipette 96-Channel pipette', }) expect(singleMountPipettes).toHaveStyle(`background-color: ${COLORS.white}`) - expect(ninetySixPipette).toHaveStyle(`background-color: ${COLORS.blue30}`) + expect(ninetySixPipette).toHaveStyle(`background-color: ${COLORS.blue10}`) }) it('renders the correct text for the 96 channel button when there is a left pipette attached', () => { vi.mocked(getIsGantryEmpty).mockReturnValue(false) @@ -150,7 +150,7 @@ describe('ChoosePipette', () => { props = { ...props, selectedPipette: NINETY_SIX_CHANNEL } render(props) screen.getByText( - 'Detach Flex 1-Channel 1000 μL and attach 96-Channel pipette' + 'Detach Flex 1-Channel 1000 μL and Attach 96-Channel pipette' ) }) @@ -163,7 +163,7 @@ describe('ChoosePipette', () => { props = { ...props, selectedPipette: NINETY_SIX_CHANNEL } render(props) screen.getByText( - 'Detach Flex 1-Channel 1000 μL and attach 96-Channel pipette' + 'Detach Flex 1-Channel 1000 μL and Attach 96-Channel pipette' ) }) }) diff --git a/app/src/organisms/PipetteWizardFlows/__tests__/Results.test.tsx b/app/src/organisms/PipetteWizardFlows/__tests__/Results.test.tsx index bf5a1d4d7aa..b0cb919531c 100644 --- a/app/src/organisms/PipetteWizardFlows/__tests__/Results.test.tsx +++ b/app/src/organisms/PipetteWizardFlows/__tests__/Results.test.tsx @@ -12,6 +12,7 @@ import { useInstrumentsQuery } from '@opentrons/react-api-client' import { renderWithProviders } from '../../../__testing-utils__' import { mockAttachedPipetteInformation } from '../../../redux/pipettes/__fixtures__' +import { useIsOEMMode } from '../../../resources/robot-settings/hooks' import { i18n } from '../../../i18n' import { RUN_ID_1 } from '../../RunTimeControl/__fixtures__' import { Results } from '../Results' @@ -20,6 +21,7 @@ import { FLOWS } from '../constants' import type { Mock } from 'vitest' vi.mock('@opentrons/react-api-client') +vi.mock('../../../resources/robot-settings/hooks') const render = (props: React.ComponentProps) => { return renderWithProviders(, { @@ -57,6 +59,7 @@ describe('Results', () => { vi.mocked(useInstrumentsQuery).mockReturnValue({ refetch: mockRefetchInstruments, } as any) + vi.mocked(useIsOEMMode).mockReturnValue(false) }) it('renders the correct information when pipette cal is a success for calibrate flow', () => { props = { diff --git a/app/src/organisms/PipetteWizardFlows/index.tsx b/app/src/organisms/PipetteWizardFlows/index.tsx index 1a671fb31fb..337a51028ed 100644 --- a/app/src/organisms/PipetteWizardFlows/index.tsx +++ b/app/src/organisms/PipetteWizardFlows/index.tsx @@ -421,7 +421,7 @@ export const PipetteWizardFlows = ( currentStep.section === SECTIONS.BEFORE_BEGINNING && selectedPipette === NINETY_SIX_CHANNEL && flowType === FLOWS.ATTACH - ? '70%' + ? '30rem' : 'auto' } header={wizardHeader} diff --git a/app/src/organisms/ProtocolDetails/ProtocolLabwareDetails.tsx b/app/src/organisms/ProtocolDetails/ProtocolLabwareDetails.tsx index 7410fd9b2cf..0f208869825 100644 --- a/app/src/organisms/ProtocolDetails/ProtocolLabwareDetails.tsx +++ b/app/src/organisms/ProtocolDetails/ProtocolLabwareDetails.tsx @@ -8,6 +8,7 @@ import { DIRECTION_ROW, Flex, Icon, + InfoScreen, POSITION_ABSOLUTE, POSITION_RELATIVE, SPACING, @@ -55,36 +56,42 @@ export const ProtocolLabwareDetails = ( : [] return ( - - - - {t('labware_name')} - - - {t('quantity')} - - - {labwareDetails?.map((labware, index) => ( - - ))} - + <> + {labwareDetails.length > 0 ? ( + + + + {t('labware_name')} + + + {t('quantity')} + + + {labwareDetails?.map((labware, index) => ( + + ))} + + ) : ( + + )} + ) } diff --git a/app/src/organisms/ProtocolDetails/ProtocolLiquidsDetails.tsx b/app/src/organisms/ProtocolDetails/ProtocolLiquidsDetails.tsx index 5aff2a28ea4..52ddf497bb7 100644 --- a/app/src/organisms/ProtocolDetails/ProtocolLiquidsDetails.tsx +++ b/app/src/organisms/ProtocolDetails/ProtocolLiquidsDetails.tsx @@ -76,7 +76,7 @@ export const ProtocolLiquidsDetails = ( borderRadius={BORDERS.borderRadius8} > - !SINGLE_SLOT_FIXTURES.includes( + ![...SINGLE_SLOT_FIXTURES, ...FLEX_USB_MODULE_FIXTURES].includes( fixture.cutoutFixtureId as SingleSlotCutoutFixtureId ) ) @@ -176,9 +180,23 @@ export const RobotConfigurationDetails = ( - {getFixtureDisplayName(fixture.cutoutFixtureId)} - + <> + {MAGNETIC_BLOCK_FIXTURES.includes(fixture.cutoutFixtureId) ? ( + + ) : null} + + {getFixtureDisplayName(fixture.cutoutFixtureId)} + + } /> diff --git a/app/src/organisms/ProtocolDetails/__tests__/ProtocolLabwareDetails.test.tsx b/app/src/organisms/ProtocolDetails/__tests__/ProtocolLabwareDetails.test.tsx index 90d4bd61af2..14f1f956295 100644 --- a/app/src/organisms/ProtocolDetails/__tests__/ProtocolLabwareDetails.test.tsx +++ b/app/src/organisms/ProtocolDetails/__tests__/ProtocolLabwareDetails.test.tsx @@ -1,12 +1,21 @@ import * as React from 'react' import { screen } from '@testing-library/react' -import { describe, it, beforeEach } from 'vitest' +import { describe, it, beforeEach, vi } from 'vitest' +import { InfoScreen } from '@opentrons/components' import { renderWithProviders } from '../../../__testing-utils__' import { i18n } from '../../../i18n' import { ProtocolLabwareDetails } from '../ProtocolLabwareDetails' import type { LoadLabwareRunTimeCommand } from '@opentrons/shared-data' +vi.mock('@opentrons/components', async importOriginal => { + const actual = await importOriginal() + return { + ...actual, + InfoScreen: vi.fn(), + } +}) + const mockRequiredLabwareDetails = [ { id: '568fd127-5554-4e19-b303-a8aeb6d8547d', @@ -70,6 +79,7 @@ describe('ProtocolLabwareDetails', () => { props = { requiredLabwareDetails: mockRequiredLabwareDetails, } + vi.mocked(InfoScreen).mockReturnValue(
mock InfoScreen
) }) it('should render an opentrons labware', () => { @@ -136,4 +146,12 @@ describe('ProtocolLabwareDetails', () => { screen.getByText('Quantity') screen.getByText('2') }) + + it('should render mock infoscreen when no labware', () => { + props = { + requiredLabwareDetails: [], + } + render(props) + screen.getByText('mock InfoScreen') + }) }) diff --git a/app/src/organisms/ProtocolDetails/index.tsx b/app/src/organisms/ProtocolDetails/index.tsx index 2dc5ecda65f..1be2faa6390 100644 --- a/app/src/organisms/ProtocolDetails/index.tsx +++ b/app/src/organisms/ProtocolDetails/index.tsx @@ -43,7 +43,9 @@ import { parseInitialLoadedLabwareByAdapter, } from '@opentrons/api-client' import { + MAGNETIC_BLOCK_TYPE, getGripperDisplayName, + getModuleType, getSimplestDeckConfigForProtocol, } from '@opentrons/shared-data' @@ -236,7 +238,13 @@ export function ProtocolDetails( const requiredModuleDetails = mostRecentAnalysis?.commands != null - ? map(parseInitialLoadedModulesBySlot(mostRecentAnalysis.commands)) + ? map( + parseInitialLoadedModulesBySlot(mostRecentAnalysis.commands) + ).filter( + loadedModule => + // filter out magnetic block which is already handled by the required fixture details + getModuleType(loadedModule.params.model) !== MAGNETIC_BLOCK_TYPE + ) : [] const requiredFixtureDetails = getSimplestDeckConfigForProtocol( @@ -591,7 +599,7 @@ export function ProtocolDetails( marginLeft={SPACING.spacing16} gridGap={SPACING.spacing8} > - + {mostRecentAnalysis != null && ( { vi.mocked(useUpdateDeckConfigurationMutation).mockReturnValue({ updateDeckConfiguration: mockUpdateDeckConfiguration, } as any) - vi.mocked(useDeckConfigurationQuery).mockReturnValue(({ + vi.mocked(useNotifyDeckConfigurationQuery).mockReturnValue(({ data: [], } as unknown) as UseQueryResult) + vi.mocked(useModulesQuery).mockReturnValue(({ + data: { data: [] }, + } as unknown) as UseQueryResult) }) afterEach(() => { diff --git a/app/src/organisms/ProtocolSetupDeckConfiguration/index.tsx b/app/src/organisms/ProtocolSetupDeckConfiguration/index.tsx index 98e977fb92a..c3c65e6318f 100644 --- a/app/src/organisms/ProtocolSetupDeckConfiguration/index.tsx +++ b/app/src/organisms/ProtocolSetupDeckConfiguration/index.tsx @@ -11,24 +11,28 @@ import { } from '@opentrons/components' import { FLEX_ROBOT_TYPE, + FLEX_SINGLE_SLOT_BY_CUTOUT_ID, + MAGNETIC_BLOCK_V1_FIXTURE, + MODULE_FIXTURES_BY_MODEL, + STAGING_AREA_SLOT_WITH_MAGNETIC_BLOCK_V1_FIXTURE, getSimplestDeckConfigForProtocol, } from '@opentrons/shared-data' -import { - useDeckConfigurationQuery, - useUpdateDeckConfigurationMutation, -} from '@opentrons/react-api-client' +import { useUpdateDeckConfigurationMutation } from '@opentrons/react-api-client' import { ChildNavigation } from '../ChildNavigation' import { AddFixtureModal } from '../DeviceDetailsDeckConfiguration/AddFixtureModal' import { DeckConfigurationDiscardChangesModal } from '../DeviceDetailsDeckConfiguration/DeckConfigurationDiscardChangesModal' import { useMostRecentCompletedAnalysis } from '../LabwarePositionCheck/useMostRecentCompletedAnalysis' import { getTopPortalEl } from '../../App/portal' +import { useNotifyDeckConfigurationQuery } from '../../resources/deck_configuration' import type { CutoutFixtureId, CutoutId, DeckConfiguration, + ModuleModel, } from '@opentrons/shared-data' +import type { ModuleOnDeck } from '@opentrons/components' import type { SetupScreens } from '../../pages/ProtocolSetup' interface ProtocolSetupDeckConfigurationProps { @@ -56,7 +60,7 @@ export function ProtocolSetupDeckConfiguration({ ] = React.useState(false) const mostRecentAnalysis = useMostRecentCompletedAnalysis(runId) - const { data: deckConfig = [] } = useDeckConfigurationQuery() + const deckConfig = useNotifyDeckConfigurationQuery()?.data ?? [] const simplestDeckConfig = getSimplestDeckConfigForProtocol( mostRecentAnalysis @@ -76,6 +80,42 @@ export function ProtocolSetupDeckConfiguration({ currentDeckConfig, setCurrentDeckConfig, ] = React.useState(mergedDeckConfig) + const modulesOnDeck = currentDeckConfig.reduce( + (acc, cutoutConfig) => { + const matchingFixtureIdsAndModel = Object.entries( + MODULE_FIXTURES_BY_MODEL + ).find(([_moduleModel, moduleFixtureIds]) => + moduleFixtureIds.includes(cutoutConfig.cutoutFixtureId) + ) + if (matchingFixtureIdsAndModel != null) { + const [matchingModel] = matchingFixtureIdsAndModel + return [ + ...acc, + { + moduleModel: matchingModel as ModuleModel, + moduleLocation: { + slotName: FLEX_SINGLE_SLOT_BY_CUTOUT_ID[cutoutConfig.cutoutId], + }, + }, + ] + } else if ( + cutoutConfig.cutoutFixtureId === + STAGING_AREA_SLOT_WITH_MAGNETIC_BLOCK_V1_FIXTURE + ) { + return [ + ...acc, + { + moduleModel: MAGNETIC_BLOCK_V1_FIXTURE, + moduleLocation: { + slotName: FLEX_SINGLE_SLOT_BY_CUTOUT_ID[cutoutConfig.cutoutId], + }, + }, + ] + } + return acc + }, + [] + ) const { updateDeckConfiguration } = useUpdateDeckConfigurationMutation() const handleClickConfirm = (): void => { @@ -120,6 +160,7 @@ export function ProtocolSetupDeckConfiguration({ diff --git a/app/src/organisms/ProtocolSetupInstruments/__tests__/ProtocolSetupInstruments.test.tsx b/app/src/organisms/ProtocolSetupInstruments/__tests__/ProtocolSetupInstruments.test.tsx index 7ab8f2b97b1..bcfc0ecf1d6 100644 --- a/app/src/organisms/ProtocolSetupInstruments/__tests__/ProtocolSetupInstruments.test.tsx +++ b/app/src/organisms/ProtocolSetupInstruments/__tests__/ProtocolSetupInstruments.test.tsx @@ -12,6 +12,7 @@ import { import { renderWithProviders } from '../../../__testing-utils__' import { i18n } from '../../../i18n' import { useMostRecentCompletedAnalysis } from '../../../organisms/LabwarePositionCheck/useMostRecentCompletedAnalysis' +import { useIsOEMMode } from '../../../resources/robot-settings/hooks' import { mockRecentAnalysis } from '../__fixtures__' import { ProtocolSetupInstruments } from '..' @@ -19,6 +20,7 @@ vi.mock('@opentrons/react-api-client') vi.mock( '../../../organisms/LabwarePositionCheck/useMostRecentCompletedAnalysis' ) +vi.mock('../../../resources/robot-settings/hooks') const mockGripperData = { instrumentModel: 'gripper_v1', @@ -71,6 +73,7 @@ describe('ProtocolSetupInstruments', () => { data: [mockLeftPipetteData, mockRightPipetteData, mockGripperData], }, } as any) + vi.mocked(useIsOEMMode).mockReturnValue(false) }) afterEach(() => { vi.resetAllMocks() diff --git a/app/src/organisms/ProtocolSetupLabware/__tests__/ProtocolSetupLabware.test.tsx b/app/src/organisms/ProtocolSetupLabware/__tests__/ProtocolSetupLabware.test.tsx index 57d7981c138..7bfb4f63871 100644 --- a/app/src/organisms/ProtocolSetupLabware/__tests__/ProtocolSetupLabware.test.tsx +++ b/app/src/organisms/ProtocolSetupLabware/__tests__/ProtocolSetupLabware.test.tsx @@ -8,7 +8,10 @@ import { useCreateLiveCommandMutation, useModulesQuery, } from '@opentrons/react-api-client' -import { ot3StandardDeckV4 as ot3StandardDeckDef } from '@opentrons/shared-data' +import { + HEATERSHAKER_MODULE_V1_FIXTURE, + ot3StandardDeckV5 as ot3StandardDeckDef, +} from '@opentrons/shared-data' import { renderWithProviders } from '../../../__testing-utils__' import { i18n } from '../../../i18n' @@ -24,6 +27,7 @@ import { mockUseModulesQueryOpening, mockUseModulesQueryUnknown, } from '../__fixtures__' +import { useNotifyDeckConfigurationQuery } from '../../../resources/deck_configuration' import type * as ReactApiClient from '@opentrons/react-api-client' @@ -40,6 +44,7 @@ vi.mock( '../../../organisms/LabwarePositionCheck/useMostRecentCompletedAnalysis' ) vi.mock('../../Devices/ProtocolRun/utils/getProtocolModulesInfo') +vi.mock('../../../resources/deck_configuration') const RUN_ID = "otie's run" const mockSetSetupScreen = vi.fn() @@ -76,6 +81,16 @@ describe('ProtocolSetupLabware', () => { vi.mocked(useCreateLiveCommandMutation).mockReturnValue({ createLiveCommand: mockCreateLiveCommand, } as any) + vi.mocked(useNotifyDeckConfigurationQuery).mockReturnValue({ + data: [ + { + cutoutId: 'cutoutB1', + cutoutFixtureId: HEATERSHAKER_MODULE_V1_FIXTURE, + opentronsModuleSerialNumber: + mockUseModulesQueryClosed.data.data[0].serialNumber, + }, + ], + } as any) }) afterEach(() => { vi.clearAllMocks() diff --git a/app/src/organisms/ProtocolSetupLabware/index.tsx b/app/src/organisms/ProtocolSetupLabware/index.tsx index bdb68944a67..831d0a57962 100644 --- a/app/src/organisms/ProtocolSetupLabware/index.tsx +++ b/app/src/organisms/ProtocolSetupLabware/index.tsx @@ -50,6 +50,8 @@ import { getNestedLabwareInfo, NestedLabwareInfo, } from '../Devices/ProtocolRun/SetupLabware/getNestedLabwareInfo' +import { LabwareMapViewModal } from './LabwareMapViewModal' +import { useNotifyDeckConfigurationQuery } from '../../resources/deck_configuration' import type { UseQueryResult } from 'react-query' import type { @@ -62,9 +64,9 @@ import type { HeaterShakerModule, Modules } from '@opentrons/api-client' import type { LabwareSetupItem } from '../../pages/Protocols/utils' import type { SetupScreens } from '../../pages/ProtocolSetup' import type { AttachedProtocolModuleMatch } from '../ProtocolSetupModulesAndDeck/utils' -import { LabwareMapViewModal } from './LabwareMapViewModal' -const MODULE_REFETCH_INTERVAL = 5000 +const MODULE_REFETCH_INTERVAL_MS = 5000 +const DECK_CONFIG_POLL_MS = 5000 const LabwareThumbnail = styled.svg` transform: scale(1, -1); @@ -97,20 +99,25 @@ export function ProtocolSetupLabware({ const mostRecentAnalysis = useMostRecentCompletedAnalysis(runId) const deckDef = getDeckDefFromRobotType(FLEX_ROBOT_TYPE) + const { data: deckConfig = [] } = useNotifyDeckConfigurationQuery({ + refetchInterval: DECK_CONFIG_POLL_MS, + }) const { offDeckItems, onDeckItems } = getLabwareSetupItemGroups( mostRecentAnalysis?.commands ?? [] ) const moduleQuery = useModulesQuery({ - refetchInterval: MODULE_REFETCH_INTERVAL, + refetchInterval: MODULE_REFETCH_INTERVAL_MS, }) const attachedModules = moduleQuery?.data?.data ?? [] const protocolModulesInfo = mostRecentAnalysis != null ? getProtocolModulesInfo(mostRecentAnalysis, deckDef) : [] + const attachedProtocolModuleMatches = getAttachedProtocolModuleMatches( attachedModules, - protocolModulesInfo + protocolModulesInfo, + deckConfig ) const initialLoadedLabwareByAdapter = parseInitialLoadedLabwareByAdapter( mostRecentAnalysis?.commands ?? [] diff --git a/app/src/organisms/ProtocolSetupModulesAndDeck/FixtureTable.tsx b/app/src/organisms/ProtocolSetupModulesAndDeck/FixtureTable.tsx index e2dbb107379..b094cc48519 100644 --- a/app/src/organisms/ProtocolSetupModulesAndDeck/FixtureTable.tsx +++ b/app/src/organisms/ProtocolSetupModulesAndDeck/FixtureTable.tsx @@ -5,7 +5,6 @@ import { BORDERS, COLORS, Chip, - DIRECTION_COLUMN, DIRECTION_ROW, Flex, JUSTIFY_SPACE_BETWEEN, @@ -15,7 +14,9 @@ import { TYPOGRAPHY, } from '@opentrons/components' import { + FLEX_USB_MODULE_ADDRESSABLE_AREAS, getCutoutDisplayName, + getDeckDefFromRobotType, getFixtureDisplayName, getSimplestDeckConfigForProtocol, SINGLE_SLOT_FIXTURES, @@ -30,10 +31,13 @@ import type { CompletedProtocolAnalysis, CutoutFixtureId, CutoutId, + DeckDefinition, RobotType, } from '@opentrons/shared-data' import type { SetupScreens } from '../../pages/ProtocolSetup' import type { CutoutConfigAndCompatibility } from '../../resources/deck_configuration/hooks' +import { useSelector } from 'react-redux' +import { getLocalRobot } from '../../redux/discovery' interface FixtureTableProps { robotType: RobotType @@ -43,6 +47,11 @@ interface FixtureTableProps { setProvidedFixtureOptions: (providedFixtureOptions: CutoutFixtureId[]) => void } +/** + * Table of all "non-module" fixtures e.g. staging slot, waste chute, trash bin... + * @param props + * @returns JSX.Element + */ export function FixtureTable({ robotType, mostRecentAnalysis, @@ -50,8 +59,6 @@ export function FixtureTable({ setCutoutId, setProvidedFixtureOptions, }: FixtureTableProps): JSX.Element | null { - const { t } = useTranslation('protocol_setup') - const requiredFixtureDetails = getSimplestDeckConfigForProtocol( mostRecentAnalysis ) @@ -59,6 +66,9 @@ export function FixtureTable({ robotType, mostRecentAnalysis ) + const deckDef = getDeckDefFromRobotType(robotType) + const localRobot = useSelector(getLocalRobot) + const robotName = localRobot?.name != null ? localRobot.name : '' const requiredDeckConfigCompatibility = getRequiredDeckConfig( deckConfigCompatibility @@ -74,21 +84,13 @@ export function FixtureTable({ ) return sortedDeckConfigCompatibility.length > 0 ? ( - - - {t('fixture')} - {t('location')} - {t('status')} - + <> {sortedDeckConfigCompatibility.map((fixtureCompatibility, index) => { - return ( + // filter out all fixtures that only provide module addressable areas (e.g. everything but StagingAreaWithMagBlockV1) + // as they're handled in the Modules Table + return fixtureCompatibility.requiredAddressableAreas.every(raa => + FLEX_USB_MODULE_ADDRESSABLE_AREAS.includes(raa) + ) ? null : ( ) })} - + ) : null } @@ -108,6 +112,8 @@ interface FixtureTableItemProps extends CutoutConfigAndCompatibility { setSetupScreen: React.Dispatch> setCutoutId: (cutoutId: CutoutId) => void setProvidedFixtureOptions: (providedFixtureOptions: CutoutFixtureId[]) => void + deckDef: DeckDefinition + robotName: string } function FixtureTableItem({ @@ -119,6 +125,8 @@ function FixtureTableItem({ setSetupScreen, setCutoutId, setProvidedFixtureOptions, + deckDef, + robotName, }: FixtureTableItemProps): JSX.Element { const { t, i18n } = useTranslation('protocol_setup') @@ -183,6 +191,8 @@ function FixtureTableItem({ requiredFixtureId={compatibleCutoutFixtureIds[0]} isOnDevice={true} missingLabwareDisplayName={missingLabwareDisplayName} + deckDef={deckDef} + robotName={robotName} /> ) : null} > } export function ModuleTable(props: ModuleTableProps): JSX.Element { - const { - attachedProtocolModuleMatches, - deckDef, - protocolModulesInfo, - runId, - setShowMultipleModulesModal, - } = props - - const { t } = useTranslation('protocol_setup') + const { attachedProtocolModuleMatches, deckDef, runId } = props const [ prepCommandErrorMessage, setPrepCommandErrorMessage, ] = React.useState('') - const { data: deckConfig } = useDeckConfigurationQuery({ + const { data: deckConfig } = useNotifyDeckConfigurationQuery({ refetchInterval: DECK_CONFIG_REFETCH_INTERVAL, }) const localRobot = useSelector(getLocalRobot) @@ -81,71 +67,42 @@ export function ModuleTable(props: ModuleTableProps): JSX.Element { const { chainLiveCommands, isCommandMutationLoading } = useChainLiveCommands() return ( - - - {t('module')} - {t('location')} - {t('status')} - + <> {attachedProtocolModuleMatches.map(module => { - // check for duplicate module model in list of modules for protocol - const isDuplicateModuleModel = protocolModulesInfo - // filter out current module - .filter(otherModule => otherModule.moduleId !== module.moduleId) - // check for existence of another module of same model - .some( - otherModule => - otherModule.moduleDef.model === module.moduleDef.model - ) - - const cutoutIdForSlotName = getCutoutIdForSlotName( + // filter out the magnetic block here, because it is handled by the SetupFixturesList + if (module.moduleDef.moduleType === MAGNETIC_BLOCK_TYPE) return null + const moduleFixtures = getCutoutFixturesForModuleModel( + module.moduleDef.model, + deckDef + ) + const moduleCutoutIds = getCutoutIdsFromModuleSlotName( module.slotName, + moduleFixtures, deckDef ) - - const isMagneticBlockModule = - module.moduleDef.moduleType === MAGNETIC_BLOCK_TYPE - - const isThermocycler = - module.moduleDef.moduleType === THERMOCYCLER_MODULE_TYPE - const conflictedFixture = deckConfig?.find( - fixture => - (fixture.cutoutId === cutoutIdForSlotName || - // special-case A1 for the thermocycler to require a single slot fixture - (fixture.cutoutId === 'cutoutA1' && isThermocycler)) && - fixture.cutoutFixtureId != null && - // do not generate a conflict for single slot fixtures, because modules are not yet fixtures - !SINGLE_SLOT_FIXTURES.includes(fixture.cutoutFixtureId) && - // special case the magnetic module because unlike other modules it sits in a slot that can also be provided by a staging area fixture - (!isMagneticBlockModule || - fixture.cutoutFixtureId !== STAGING_AREA_RIGHT_SLOT_FIXTURE) + ({ cutoutId, cutoutFixtureId }) => + moduleCutoutIds.includes(cutoutId) && + !moduleFixtures.some(({ id }) => cutoutFixtureId === id) && + module.attachedModuleMatch == null ) ?? null - return ( ) })} - + ) } @@ -156,24 +113,24 @@ interface ModuleTableItemProps { continuePastCommandFailure: boolean ) => Promise conflictedFixture: CutoutConfig | null - isDuplicateModuleModel: boolean isLoading: boolean module: AttachedProtocolModuleMatch prepCommandErrorMessage: string setPrepCommandErrorMessage: React.Dispatch> - setShowMultipleModulesModal: React.Dispatch> + deckDef: DeckDefinition + robotName: string } function ModuleTableItem({ - isDuplicateModuleModel, module, - setShowMultipleModulesModal, calibrationStatus, chainLiveCommands, isLoading, prepCommandErrorMessage, setPrepCommandErrorMessage, conflictedFixture, + deckDef, + robotName, }: ModuleTableItemProps): JSX.Element { const { i18n, t } = useTranslation(['protocol_setup', 'module_wizard_flows']) @@ -216,7 +173,6 @@ function ModuleTableItem({ background={false} iconName="connection-status" /> - {isDuplicateModuleModel ? : null} ) if (conflictedFixture != null) { @@ -231,7 +187,9 @@ function ModuleTableItem({ setShowLocationConflictModal(true)} + onClick={() => { + setShowLocationConflictModal(true) + }} /> ) @@ -246,17 +204,12 @@ function ModuleTableItem({ module.attachedModuleMatch?.moduleOffset?.last_modified != null ) { moduleStatus = ( - <> - - {isDuplicateModuleModel ? ( - - ) : null} - + ) } else if ( isModuleReady && @@ -285,8 +238,9 @@ function ModuleTableItem({ {showModuleWizard && module.attachedModuleMatch != null ? ( setShowModuleWizard(false)} - initialSlotName={module.slotName} + closeFlow={() => { + setShowModuleWizard(false) + }} isPrepCommandLoading={isLoading} prepCommandErrorMessage={ prepCommandErrorMessage === '' ? undefined : prepCommandErrorMessage @@ -295,10 +249,14 @@ function ModuleTableItem({ ) : null} {showLocationConflictModal && conflictedFixture != null ? ( setShowLocationConflictModal(false)} + onCloseClick={() => { + setShowLocationConflictModal(false) + }} cutoutId={conflictedFixture.cutoutId} requiredModule={module.moduleDef.model} + deckDef={deckDef} isOnDevice={true} + robotName={robotName} /> ) : null} - isDuplicateModuleModel ? setShowMultipleModulesModal(true) : null - } > diff --git a/app/src/organisms/ProtocolSetupModulesAndDeck/SetupInstructionsModal.tsx b/app/src/organisms/ProtocolSetupModulesAndDeck/SetupInstructionsModal.tsx index 7fbbf4f048e..c7acb6f2a42 100644 --- a/app/src/organisms/ProtocolSetupModulesAndDeck/SetupInstructionsModal.tsx +++ b/app/src/organisms/ProtocolSetupModulesAndDeck/SetupInstructionsModal.tsx @@ -26,7 +26,7 @@ interface SetupInstructionsModalProps { export function SetupInstructionsModal({ setShowSetupInstructionsModal, }: SetupInstructionsModalProps): JSX.Element { - const { i18n, t } = useTranslation('protocol_setup') + const { i18n, t } = useTranslation(['protocol_setup', 'branded']) const modalHeader: ModalHeaderBaseProps = { title: i18n.format(t('setup_instructions'), 'capitalize'), iconName: 'information', @@ -45,7 +45,9 @@ export function SetupInstructionsModal({ gridGap={SPACING.spacing40} > - {t('setup_instructions_description')} + + {t('branded:setup_instructions_description')} + { setCutoutId: mockSetCutoutId, setProvidedFixtureOptions: mockSetProvidedFixtureOptions, } + vi.mocked(getLocalRobot).mockReturnValue(mockConnectedRobot) vi.mocked(LocationConflictModal).mockReturnValue(
mock location conflict modal
) @@ -60,13 +64,6 @@ describe('FixtureTable', () => { vi.clearAllMocks() }) - it('should render table header and contents', () => { - render(props) - screen.getByText('Fixture') - screen.getByText('Location') - screen.getByText('Status') - }) - it('should render the current status - configured', () => { render(props) screen.getByText('Configured') diff --git a/app/src/organisms/ProtocolSetupModulesAndDeck/__tests__/ProtocolSetupModulesAndDeck.test.tsx b/app/src/organisms/ProtocolSetupModulesAndDeck/__tests__/ProtocolSetupModulesAndDeck.test.tsx index ead32d65d38..e2bd427d691 100644 --- a/app/src/organisms/ProtocolSetupModulesAndDeck/__tests__/ProtocolSetupModulesAndDeck.test.tsx +++ b/app/src/organisms/ProtocolSetupModulesAndDeck/__tests__/ProtocolSetupModulesAndDeck.test.tsx @@ -5,7 +5,6 @@ import { vi, it, expect, describe, beforeEach, afterEach } from 'vitest' import { when } from 'vitest-when' import { MemoryRouter } from 'react-router-dom' -import { useDeckConfigurationQuery } from '@opentrons/react-api-client' import { FLEX_ROBOT_TYPE, WASTE_CHUTE_RIGHT_ADAPTER_NO_COVER_FIXTURE, @@ -36,13 +35,16 @@ import { SetupInstructionsModal } from '../SetupInstructionsModal' import { FixtureTable } from '../FixtureTable' import { ModulesAndDeckMapViewModal } from '../ModulesAndDeckMapViewModal' import { ProtocolSetupModulesAndDeck } from '..' +import { useNotifyDeckConfigurationQuery } from '../../../resources/deck_configuration' +import { useRunStatus } from '../../RunTimeControl/hooks' import type { CutoutConfig, DeckConfiguration } from '@opentrons/shared-data' +import { RUN_STATUS_IDLE } from '@opentrons/api-client' -vi.mock('@opentrons/react-api-client') vi.mock('../../../resources/runs') vi.mock('../../../redux/discovery') vi.mock('../../../organisms/Devices/hooks') +vi.mock('../../../resources/deck_configuration') vi.mock( '../../../organisms/LabwarePositionCheck/useMostRecentCompletedAnalysis' ) @@ -53,6 +55,7 @@ vi.mock('../../ModuleWizardFlows') vi.mock('../FixtureTable') vi.mock('../../Devices/ProtocolRun/SetupModuleAndDeck/LocationConflictModal') vi.mock('../ModulesAndDeckMapViewModal') +vi.mock('../../RunTimeControl/hooks') const ROBOT_NAME = 'otie' const RUN_ID = '1' @@ -107,7 +110,7 @@ describe('ProtocolSetupModulesAndDeck', () => { .calledWith(mockRobotSideAnalysis, flexDeckDef) .thenReturn([]) when(vi.mocked(getAttachedProtocolModuleMatches)) - .calledWith([], []) + .calledWith([], [], []) .thenReturn([]) when(vi.mocked(getUnmatchedModulesForProtocol)) .calledWith([], []) @@ -119,7 +122,7 @@ describe('ProtocolSetupModulesAndDeck', () => { vi.mocked(LocationConflictModal).mockReturnValue(
mock location conflict modal
) - vi.mocked(useDeckConfigurationQuery).mockReturnValue(({ + vi.mocked(useNotifyDeckConfigurationQuery).mockReturnValue(({ data: [], } as unknown) as UseQueryResult) when(vi.mocked(useRunCalibrationStatus)) @@ -134,6 +137,7 @@ describe('ProtocolSetupModulesAndDeck', () => { chainLiveCommands: mockChainLiveCommands, } as any) vi.mocked(FixtureTable).mockReturnValue(
mock FixtureTable
) + vi.mocked(useRunStatus).mockReturnValue(RUN_STATUS_IDLE) }) afterEach(() => { @@ -148,7 +152,7 @@ describe('ProtocolSetupModulesAndDeck', () => { }, ]) render() - screen.getByText('Module') + screen.getByText('Deck hardware') screen.getByText('Location') screen.getByText('Status') screen.getByText('Setup Instructions') @@ -307,13 +311,13 @@ describe('ProtocolSetupModulesAndDeck', () => { }) it('should render mock Fixture table and module location conflict', () => { - vi.mocked(useDeckConfigurationQuery).mockReturnValue({ + vi.mocked(useNotifyDeckConfigurationQuery).mockReturnValue({ data: [mockFixture], } as UseQueryResult) vi.mocked(getAttachedProtocolModuleMatches).mockReturnValue([ { ...mockProtocolModuleInfo[0], - attachedModuleMatch: calibratedMockApiHeaterShaker, + attachedModuleMatch: undefined, slotName: 'D3', }, ]) diff --git a/app/src/organisms/ProtocolSetupModulesAndDeck/__tests__/utils.test.tsx b/app/src/organisms/ProtocolSetupModulesAndDeck/__tests__/utils.test.tsx index 97c76148799..b96d972ca36 100644 --- a/app/src/organisms/ProtocolSetupModulesAndDeck/__tests__/utils.test.tsx +++ b/app/src/organisms/ProtocolSetupModulesAndDeck/__tests__/utils.test.tsx @@ -1,7 +1,10 @@ import { describe, it, expect } from 'vitest' -import { getModuleDef2 } from '@opentrons/shared-data' +import { + TEMPERATURE_MODULE_V2_FIXTURE, + getModuleDef2, +} from '@opentrons/shared-data' -import { mockTemperatureModule } from '../../../redux/modules/__fixtures__' +import { mockTemperatureModuleGen2 } from '../../../redux/modules/__fixtures__' import { getAttachedProtocolModuleMatches, getUnmatchedModulesForProtocol, @@ -12,7 +15,7 @@ const temperatureProtocolModule = { x: 0, y: 0, z: 0, - moduleDef: getModuleDef2('temperatureModuleV1'), + moduleDef: getModuleDef2('temperatureModuleV2'), nestedLabwareDef: null, nestedLabwareId: null, nestedLabwareDisplayName: null, @@ -37,7 +40,8 @@ describe('getAttachedProtocolModuleMatches', () => { it('returns no module matches when no modules attached', () => { const result = getAttachedProtocolModuleMatches( [], - [temperatureProtocolModule, magneticProtocolModule] + [temperatureProtocolModule, magneticProtocolModule], + [] ) expect(result).toEqual([ { ...temperatureProtocolModule, attachedModuleMatch: null }, @@ -47,8 +51,15 @@ describe('getAttachedProtocolModuleMatches', () => { it('returns no module matches when no modules match', () => { const result = getAttachedProtocolModuleMatches( - [mockTemperatureModule], - [magneticProtocolModule] + [mockTemperatureModuleGen2], + [magneticProtocolModule], + [ + { + cutoutId: 'cutoutD1', + cutoutFixtureId: TEMPERATURE_MODULE_V2_FIXTURE, + opentronsModuleSerialNumber: mockTemperatureModuleGen2.serialNumber, + }, + ] ) expect(result).toEqual([ { ...magneticProtocolModule, attachedModuleMatch: null }, @@ -57,13 +68,20 @@ describe('getAttachedProtocolModuleMatches', () => { it('returns module match when modules match', () => { const result = getAttachedProtocolModuleMatches( - [mockTemperatureModule], - [temperatureProtocolModule, magneticProtocolModule] + [mockTemperatureModuleGen2], + [temperatureProtocolModule, magneticProtocolModule], + [ + { + cutoutId: 'cutoutD1', + cutoutFixtureId: TEMPERATURE_MODULE_V2_FIXTURE, + opentronsModuleSerialNumber: mockTemperatureModuleGen2.serialNumber, + }, + ] ) expect(result).toEqual([ { ...temperatureProtocolModule, - attachedModuleMatch: mockTemperatureModule, + attachedModuleMatch: mockTemperatureModuleGen2, }, { ...magneticProtocolModule, attachedModuleMatch: null }, ]) @@ -81,7 +99,7 @@ describe('getUnmatchedModulesForProtocol', () => { it('returns no missing module ids or remaining attached modules when attached modules match', () => { const result = getUnmatchedModulesForProtocol( - [mockTemperatureModule], + [mockTemperatureModuleGen2], [temperatureProtocolModule] ) expect(result).toEqual({ @@ -103,12 +121,12 @@ describe('getUnmatchedModulesForProtocol', () => { it('returns remaining attached modules when protocol modules and attached modules do not match', () => { const result = getUnmatchedModulesForProtocol( - [mockTemperatureModule], + [mockTemperatureModuleGen2], [magneticProtocolModule] ) expect(result).toEqual({ missingModuleIds: ['mockMagneticModuleId'], - remainingAttachedModules: [mockTemperatureModule], + remainingAttachedModules: [mockTemperatureModuleGen2], }) }) }) diff --git a/app/src/organisms/ProtocolSetupModulesAndDeck/index.tsx b/app/src/organisms/ProtocolSetupModulesAndDeck/index.tsx index 6b72d6bf6ba..4369f8f297f 100644 --- a/app/src/organisms/ProtocolSetupModulesAndDeck/index.tsx +++ b/app/src/organisms/ProtocolSetupModulesAndDeck/index.tsx @@ -2,7 +2,14 @@ import * as React from 'react' import { createPortal } from 'react-dom' import { useTranslation } from 'react-i18next' -import { DIRECTION_COLUMN, Flex, SPACING } from '@opentrons/components' +import { + COLORS, + DIRECTION_COLUMN, + Flex, + SPACING, + StyledText, + TYPOGRAPHY, +} from '@opentrons/components' import { FLEX_ROBOT_TYPE, getDeckDefFromRobotType, @@ -13,7 +20,6 @@ import { FloatingActionButton } from '../../atoms/buttons' import { InlineNotification } from '../../atoms/InlineNotification' import { ChildNavigation } from '../../organisms/ChildNavigation' import { useAttachedModules } from '../../organisms/Devices/hooks' -import { MultipleModulesModal } from '../../organisms/Devices/ProtocolRun/SetupModuleAndDeck/MultipleModulesModal' import { getProtocolModulesInfo } from '../../organisms/Devices/ProtocolRun/utils/getProtocolModulesInfo' import { useMostRecentCompletedAnalysis } from '../../organisms/LabwarePositionCheck/useMostRecentCompletedAnalysis' import { @@ -24,11 +30,16 @@ import { SetupInstructionsModal } from './SetupInstructionsModal' import { FixtureTable } from './FixtureTable' import { ModuleTable } from './ModuleTable' import { ModulesAndDeckMapViewModal } from './ModulesAndDeckMapViewModal' +import { useNotifyDeckConfigurationQuery } from '../../resources/deck_configuration' import type { CutoutId, CutoutFixtureId } from '@opentrons/shared-data' import type { SetupScreens } from '../../pages/ProtocolSetup' +import { useRunStatus } from '../RunTimeControl/hooks' +import { RUN_STATUS_STOPPED } from '@opentrons/api-client' +import { useHistory } from 'react-router-dom' const ATTACHED_MODULE_POLL_MS = 5000 +const DECK_CONFIG_POLL_MS = 5000 interface ProtocolSetupModulesAndDeckProps { runId: string @@ -47,11 +58,13 @@ export function ProtocolSetupModulesAndDeck({ setProvidedFixtureOptions, }: ProtocolSetupModulesAndDeckProps): JSX.Element { const { i18n, t } = useTranslation('protocol_setup') - - const [ - showMultipleModulesModal, - setShowMultipleModulesModal, - ] = React.useState(false) + const history = useHistory() + const runStatus = useRunStatus(runId) + React.useEffect(() => { + if (runStatus === RUN_STATUS_STOPPED) { + history.push('/protocols') + } + }, [runStatus, history]) const [ showSetupInstructionsModal, setShowSetupInstructionsModal, @@ -64,7 +77,9 @@ export function ProtocolSetupModulesAndDeck({ const mostRecentAnalysis = useMostRecentCompletedAnalysis(runId) const deckDef = getDeckDefFromRobotType(FLEX_ROBOT_TYPE) - + const { data: deckConfig = [] } = useNotifyDeckConfigurationQuery({ + refetchInterval: DECK_CONFIG_POLL_MS, + }) const attachedModules = useAttachedModules({ refetchInterval: ATTACHED_MODULE_POLL_MS, @@ -77,7 +92,8 @@ export function ProtocolSetupModulesAndDeck({ const attachedProtocolModuleMatches = getAttachedProtocolModuleMatches( attachedModules, - protocolModulesInfo + protocolModulesInfo, + deckConfig ) const hasModules = attachedProtocolModuleMatches.length > 0 @@ -93,11 +109,6 @@ export function ProtocolSetupModulesAndDeck({ <> {createPortal( <> - {showMultipleModulesModal ? ( - setShowMultipleModulesModal(false)} - /> - ) : null} {showSetupInstructionsModal ? ( setSetupScreen('prepare to run')} buttonText={i18n.format(t('setup_instructions'), 'titleCase')} buttonType="tertiaryLowLight" @@ -126,7 +137,7 @@ export function ProtocolSetupModulesAndDeck({ {isModuleMismatch && !clearModuleMismatchBanner ? ( @@ -140,23 +151,37 @@ export function ProtocolSetupModulesAndDeck({ message={t('module_mismatch_body')} /> ) : null} - - {hasModules ? ( - + + + {i18n.format(t('deck_hardware'), 'titleCase')} + + {t('location')} + {t('status')} + + + {hasModules ? ( + + ) : null} + - ) : null} - + setShowDeckMapModal(true)} /> diff --git a/app/src/organisms/ProtocolSetupModulesAndDeck/utils.ts b/app/src/organisms/ProtocolSetupModulesAndDeck/utils.ts index 113cba73075..cc921ef6049 100644 --- a/app/src/organisms/ProtocolSetupModulesAndDeck/utils.ts +++ b/app/src/organisms/ProtocolSetupModulesAndDeck/utils.ts @@ -1,6 +1,11 @@ import { + DeckConfiguration, + FLEX_ROBOT_TYPE, NON_CONNECTING_MODULE_TYPES, checkModuleCompatibility, + getCutoutFixturesForModuleModel, + getCutoutIdsFromModuleSlotName, + getDeckDefFromRobotType, getModuleType, } from '@opentrons/shared-data' @@ -11,14 +16,26 @@ export type AttachedProtocolModuleMatch = ProtocolModuleInfo & { attachedModuleMatch: AttachedModule | null } +// NOTE: this is a FLEX only function // some logic copied from useModuleRenderInfoForProtocolById export function getAttachedProtocolModuleMatches( attachedModules: AttachedModule[], - protocolModulesInfo: ProtocolModuleInfo[] + protocolModulesInfo: ProtocolModuleInfo[], + deckConfig: DeckConfiguration ): AttachedProtocolModuleMatch[] { + const deckDef = getDeckDefFromRobotType(FLEX_ROBOT_TYPE) // this is only used for Flex ODD const matchedAttachedModules: AttachedModule[] = [] const attachedProtocolModuleMatches = protocolModulesInfo.map( protocolModule => { + const moduleFixtures = getCutoutFixturesForModuleModel( + protocolModule.moduleDef.model, + deckDef + ) + const moduleCutoutIds = getCutoutIdsFromModuleSlotName( + protocolModule.slotName, + moduleFixtures, + deckDef + ) const compatibleAttachedModule = attachedModules.find( attachedModule => @@ -27,10 +44,17 @@ export function getAttachedProtocolModuleMatches( protocolModule.moduleDef.model ) && // check id instead of object reference in useModuleRenderInfoForProtocolById - matchedAttachedModules.find( + !matchedAttachedModules.some( matchedAttachedModule => - matchedAttachedModule.id === attachedModule.id - ) == null + matchedAttachedModule.serialNumber === + attachedModule.serialNumber + ) && + // check deck config has module with expected serial number in expected location + deckConfig.some( + ({ cutoutId, opentronsModuleSerialNumber }) => + attachedModule.serialNumber === opentronsModuleSerialNumber && + moduleCutoutIds.includes(cutoutId) + ) ) ?? null if (compatibleAttachedModule !== null) { matchedAttachedModules.push(compatibleAttachedModule) diff --git a/app/src/organisms/ProtocolSetupParameters/ChooseEnum.tsx b/app/src/organisms/ProtocolSetupParameters/ChooseEnum.tsx index 60e1d7a1b03..1e49e0d8eb0 100644 --- a/app/src/organisms/ProtocolSetupParameters/ChooseEnum.tsx +++ b/app/src/organisms/ProtocolSetupParameters/ChooseEnum.tsx @@ -29,12 +29,7 @@ export function ChooseEnum({ const { makeSnackbar } = useToaster() const { t } = useTranslation(['protocol_setup', 'shared']) - if (parameter.type !== 'str') { - console.error( - `parameter type is expected to be a string for parameter ${parameter.displayName}` - ) - } - const options = parameter.type === 'str' ? parameter.choices : undefined + const options = 'choices' in parameter ? parameter.choices : null const handleOnClick = (newValue: string | number | boolean): void => { setParameter(newValue, parameter.variableName) } diff --git a/app/src/organisms/ProtocolSetupParameters/ChooseNumber.tsx b/app/src/organisms/ProtocolSetupParameters/ChooseNumber.tsx new file mode 100644 index 00000000000..d01e8766f5c --- /dev/null +++ b/app/src/organisms/ProtocolSetupParameters/ChooseNumber.tsx @@ -0,0 +1,164 @@ +import * as React from 'react' +import { useTranslation } from 'react-i18next' +import { + ALIGN_CENTER, + DIRECTION_COLUMN, + Flex, + SPACING, + StyledText, + TYPOGRAPHY, +} from '@opentrons/components' +import { InputField } from '../../atoms/InputField' +import { useToaster } from '../ToasterOven' +import { ChildNavigation } from '../ChildNavigation' +import { NumericalKeyboard } from '../../atoms/SoftwareKeyboard' +import type { NumberParameter } from '@opentrons/shared-data' + +interface ChooseNumberProps { + handleGoBack: () => void + parameter: NumberParameter + setParameter: (value: number, variableName: string) => void +} + +export function ChooseNumber({ + handleGoBack, + parameter, + setParameter, +}: ChooseNumberProps): JSX.Element | null { + const { makeSnackbar } = useToaster() + + const { i18n, t } = useTranslation(['protocol_setup', 'shared']) + const keyboardRef = React.useRef(null) + const [paramValue, setParamValue] = React.useState( + String(parameter.value) + ) + + // We need to arbitrarily set the value of the keyboard to a string the + // same length as the initial parameter value (as string) when the component mounts + // so that the delete button operates properly on the exisiting input field value. + const [prevKeyboardValue, setPrevKeyboardValue] = React.useState('') + React.useEffect(() => { + const arbitraryInput = new Array(paramValue).join('*') + // @ts-expect-error keyboard should expose for `setInput` method + keyboardRef.current?.setInput(arbitraryInput) + setPrevKeyboardValue(arbitraryInput) + }, []) + + if (parameter.type !== 'int' && parameter.type !== 'float') { + console.log(`Incorrect parameter type: ${parameter.type}`) + return null + } + const handleClickGoBack = (newValue: number): void => { + if (error != null) { + makeSnackbar(t('value_out_of_range_generic')) + } else { + setParameter(newValue, parameter.variableName) + handleGoBack() + } + } + + const handleKeyboardInput = (e: string): void => { + if (prevKeyboardValue.length < e.length) { + const lastDigit = e.slice(-1) + if ( + !'.-'.includes(lastDigit) || + (lastDigit === '.' && !paramValue.includes('.')) || + (lastDigit === '-' && paramValue.length === 0) + ) { + setParamValue(paramValue + lastDigit) + } + } else { + setParamValue(paramValue.slice(0, paramValue.length - 1)) + } + setPrevKeyboardValue(e) + } + + const paramValueAsNumber = Number(paramValue) + const resetValueDisabled = parameter.default === paramValueAsNumber + const { min, max } = parameter + const error = + paramValue === '' || + Number.isNaN(paramValueAsNumber) || + paramValueAsNumber < min || + paramValueAsNumber > max + ? t(`value_out_of_range`, { + min: parameter.type === 'int' ? min : min.toFixed(1), + max: parameter.type === 'int' ? max : max.toFixed(1), + }) + : null + + return ( + <> + { + handleClickGoBack(paramValueAsNumber) + }} + buttonType="tertiaryLowLight" + buttonText={t('restore_default')} + onClickButton={() => + resetValueDisabled + ? makeSnackbar(t('no_custom_values')) + : setParamValue(String(parameter.default)) + } + /> + + + + {parameter.description} + + { + const updatedValue = + parameter.type === 'int' + ? Math.round(e.target.valueAsNumber) + : e.target.valueAsNumber + setParamValue( + Number.isNaN(updatedValue) ? '' : String(updatedValue) + ) + }} + /> + + + { + handleKeyboardInput(e) + }} + /> + + + + ) +} diff --git a/app/src/organisms/ProtocolSetupParameters/ViewOnlyParameters.tsx b/app/src/organisms/ProtocolSetupParameters/ViewOnlyParameters.tsx index 09dcaf26c47..3ce9169f77f 100644 --- a/app/src/organisms/ProtocolSetupParameters/ViewOnlyParameters.tsx +++ b/app/src/organisms/ProtocolSetupParameters/ViewOnlyParameters.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' -import { formatRunTimeParameterDefaultValue } from '@opentrons/shared-data' +import { formatRunTimeParameterValue } from '@opentrons/shared-data' import { ALIGN_CENTER, BORDERS, @@ -16,7 +16,6 @@ import { import { useMostRecentCompletedAnalysis } from '../LabwarePositionCheck/useMostRecentCompletedAnalysis' import { ChildNavigation } from '../ChildNavigation' import { useToaster } from '../ToasterOven' -import { mockData } from './index' import type { SetupScreens } from '../../pages/ProtocolSetup' @@ -36,8 +35,7 @@ export function ViewOnlyParameters({ makeSnackbar(t('reset_setup')) } - // TODO(jr, 3/18/24): remove mockData - const parameters = mostRecentAnalysis?.runTimeParameters ?? mockData + const parameters = mostRecentAnalysis?.runTimeParameters ?? [] return ( <> @@ -68,9 +66,6 @@ export function ViewOnlyParameters({ {t('value')}
{parameters.map((parameter, index) => { - // TODO(jr, 3/20/24): plug in the info if the - // parameter changed from the default - const hasCustomValue = true return ( - - {formatRunTimeParameterDefaultValue(parameter, t)} + + {formatRunTimeParameterValue(parameter, t)} - {hasCustomValue ? ( + {parameter.value !== parameter.default ? ( { }) it('calls the prop if reset default is clicked when the default has changed', () => { render(props) - fireEvent.click(screen.getByText('Restore default values')) + fireEvent.click(screen.getByText('Restore default value')) expect(props.setParameter).toHaveBeenCalled() }) it('calls does not call prop if reset default is clicked when the default has not changed', () => { @@ -61,7 +61,7 @@ describe('ChooseEnum', () => { rawValue: 'none', } render(props) - fireEvent.click(screen.getByText('Restore default values')) + fireEvent.click(screen.getByText('Restore default value')) expect(props.setParameter).not.toHaveBeenCalled() }) it('should render the text and buttons for choice param', () => { @@ -73,7 +73,7 @@ describe('ChooseEnum', () => { const selectedOption = screen.getByRole('label', { name: 'temp offset', }) - expect(notSelectedOption).toHaveStyle(`background-color: ${COLORS.blue40}`) - expect(selectedOption).toHaveStyle(`background-color: ${COLORS.blue60}`) + expect(notSelectedOption).toHaveStyle(`background: ${COLORS.blue35}`) + expect(selectedOption).toHaveStyle(`background: ${COLORS.blue50}`) }) }) diff --git a/app/src/organisms/ProtocolSetupParameters/__tests__/ChooseNumber.test.tsx b/app/src/organisms/ProtocolSetupParameters/__tests__/ChooseNumber.test.tsx new file mode 100644 index 00000000000..1d312bc36a5 --- /dev/null +++ b/app/src/organisms/ProtocolSetupParameters/__tests__/ChooseNumber.test.tsx @@ -0,0 +1,102 @@ +import * as React from 'react' +import { it, describe, beforeEach, vi, expect } from 'vitest' +import { fireEvent, screen } from '@testing-library/react' +import '@testing-library/jest-dom/vitest' +import { renderWithProviders } from '../../../__testing-utils__' +import { i18n } from '../../../i18n' +import { useToaster } from '../../ToasterOven' +import { mockRunTimeParameterData } from '../../../pages/ProtocolDetails/fixtures' +import { ChooseNumber } from '../ChooseNumber' + +import type { NumberParameter } from '@opentrons/shared-data' + +vi.mock('../../ToasterOven') + +const mockHandleGoBack = vi.fn() +const mockIntNumberParameterData = mockRunTimeParameterData[5] as NumberParameter +const mockFloatNumberParameterData = mockRunTimeParameterData[6] as NumberParameter +const mockSetParameter = vi.fn() +const mockMakeSnackbar = vi.fn() + +const render = (props: React.ComponentProps) => { + return renderWithProviders(, { + i18nInstance: i18n, + }) +} + +describe('ChooseNumber', () => { + let props: React.ComponentProps + + beforeEach(() => { + props = { + handleGoBack: mockHandleGoBack, + parameter: mockIntNumberParameterData, + setParameter: mockSetParameter, + } + vi.clearAllMocks() + vi.mocked(useToaster).mockReturnValue({ + makeSnackbar: mockMakeSnackbar, + makeToast: vi.fn(), + eatToast: vi.fn(), + }) + }) + + it('should render text and numerical keyboard non decimal and no negative number', () => { + render(props) + expect(screen.queryByRole('button', { name: '.' })).not.toBeInTheDocument() + expect(screen.queryByRole('button', { name: '-' })).not.toBeInTheDocument() + }) + + it('should render text and numerical keyboard non decimal and negative number', () => { + const mockNegativeIntNumberParameterData = { + ...mockIntNumberParameterData, + min: -2, + } + props = { ...props, parameter: mockNegativeIntNumberParameterData } + render(props) + expect(screen.queryByRole('button', { name: '.' })).not.toBeInTheDocument() + expect(screen.getByRole('button', { name: '-' })).toBeInTheDocument() + }) + + it('should render text and numerical keyboard decimal and no negative number', () => { + props = { ...props, parameter: mockFloatNumberParameterData } + render(props) + expect(screen.getByRole('button', { name: '.' })).toBeInTheDocument() + expect(screen.queryByRole('button', { name: '-' })).not.toBeInTheDocument() + }) + + it('should render text and numerical keyboard decimal and negative number', () => { + const mockNegativeFloatNumberParameterData = { + ...mockFloatNumberParameterData, + min: -10.2, + } + props = { ...props, parameter: mockNegativeFloatNumberParameterData } + console.log(mockNegativeFloatNumberParameterData) + render(props) + expect(screen.getByRole('button', { name: '.' })).toBeInTheDocument() + expect(screen.getByRole('button', { name: '-' })).toBeInTheDocument() + }) + + it('should call mock function when tapping go back button', () => { + render(props) + fireEvent.click(screen.getAllByRole('button')[0]) + expect(mockHandleGoBack).toHaveBeenCalled() + }) + + it('should render error message when inputting an out of range number', () => { + render(props) + const numKey = screen.getByRole('button', { name: '1' }) + fireEvent.click(numKey) + fireEvent.click(numKey) + screen.getByText('Value must be between 1-10') + }) + + it('should call mock snack bar function when inputting an out of range number', () => { + render(props) + const numKey = screen.getByRole('button', { name: '1' }) + fireEvent.click(numKey) + fireEvent.click(numKey) + fireEvent.click(screen.getAllByRole('button')[0]) + expect(mockMakeSnackbar).toHaveBeenCalledWith('Value must be in range') + }) +}) diff --git a/app/src/organisms/ProtocolSetupParameters/__tests__/ProtocolSetupParameters.test.tsx b/app/src/organisms/ProtocolSetupParameters/__tests__/ProtocolSetupParameters.test.tsx index 1dc55314d59..8e156c14087 100644 --- a/app/src/organisms/ProtocolSetupParameters/__tests__/ProtocolSetupParameters.test.tsx +++ b/app/src/organisms/ProtocolSetupParameters/__tests__/ProtocolSetupParameters.test.tsx @@ -2,7 +2,11 @@ import * as React from 'react' import { when } from 'vitest-when' import { it, describe, beforeEach, vi, expect } from 'vitest' import { fireEvent, screen } from '@testing-library/react' -import { useCreateRunMutation, useHost } from '@opentrons/react-api-client' +import { + useCreateProtocolAnalysisMutation, + useCreateRunMutation, + useHost, +} from '@opentrons/react-api-client' import { i18n } from '../../../i18n' import { renderWithProviders } from '../../../__testing-utils__' import { ProtocolSetupParameters } from '..' @@ -24,6 +28,7 @@ vi.mock('react-router-dom', async importOriginal => { } }) const MOCK_HOST_CONFIG: HostConfig = { hostname: 'MOCK_HOST' } +const mockCreateProtocolAnalysis = vi.fn() const mockCreateRun = vi.fn() const render = ( props: React.ComponentProps @@ -43,10 +48,14 @@ describe('ProtocolSetupParameters', () => { } vi.mocked(ChooseEnum).mockReturnValue(
mock ChooseEnum
) vi.mocked(useHost).mockReturnValue(MOCK_HOST_CONFIG) + when(vi.mocked(useCreateProtocolAnalysisMutation)) + .calledWith(expect.anything(), expect.anything()) + .thenReturn({ createProtocolAnalysis: mockCreateProtocolAnalysis } as any) when(vi.mocked(useCreateRunMutation)) .calledWith(expect.anything()) .thenReturn({ createRun: mockCreateRun } as any) }) + it('renders the parameters labels and mock data', () => { render(props) screen.getByText('Parameters') @@ -55,28 +64,39 @@ describe('ProtocolSetupParameters', () => { screen.getByText('Dry Run') screen.getByText('a dry run description') }) + it('renders the ChooseEnum component when a str param is selected', () => { render(props) fireEvent.click(screen.getByText('Default Module Offsets')) screen.getByText('mock ChooseEnum') }) + it('renders the other setting when boolean param is selected', () => { render(props) - screen.getByText('Off') - expect(screen.getAllByText('On')).toHaveLength(3) + expect(screen.getAllByText('On')).toHaveLength(2) fireEvent.click(screen.getByText('Dry Run')) - expect(screen.getAllByText('On')).toHaveLength(4) + expect(screen.getAllByText('On')).toHaveLength(3) }) + it('renders the back icon and calls useHistory', () => { render(props) fireEvent.click(screen.getAllByRole('button')[0]) expect(mockGoBack).toHaveBeenCalled() }) + it('renders the confirm values button and clicking on it creates a run', () => { render(props) fireEvent.click(screen.getByRole('button', { name: 'Confirm values' })) expect(mockCreateRun).toHaveBeenCalled() }) + + it('should restore default values button is disabled when tapping confirm values button', async () => { + render(props) + const resetButton = screen.getByTestId('ChildNavigation_Secondary_Button') + fireEvent.click(screen.getByText('Confirm values')) + expect(resetButton).toBeDisabled() + }) + it('renders the reset values modal', () => { render(props) fireEvent.click( @@ -88,6 +108,5 @@ describe('ProtocolSetupParameters', () => { const title = screen.getByText('Reset parameter values?') fireEvent.click(screen.getByRole('button', { name: 'Go back' })) expect(title).not.toBeInTheDocument() - // TODO(jr, 3/19/24): wire up the confirm button }) }) diff --git a/app/src/organisms/ProtocolSetupParameters/__tests__/ViewOnlyParameters.test.tsx b/app/src/organisms/ProtocolSetupParameters/__tests__/ViewOnlyParameters.test.tsx index 90893117b6f..6e20fe65658 100644 --- a/app/src/organisms/ProtocolSetupParameters/__tests__/ViewOnlyParameters.test.tsx +++ b/app/src/organisms/ProtocolSetupParameters/__tests__/ViewOnlyParameters.test.tsx @@ -60,6 +60,8 @@ describe('ViewOnlyParameters', () => { fireEvent.click(screen.getAllByRole('button')[0]) expect(props.setSetupScreen).toHaveBeenCalled() }) - // TODO(jr, 3/20/24):test the update chip when - // custom value boolean is wired up + it('renders chip for updated values', () => { + render(props) + screen.getByTestId('Chip_USE_GRIPPER') + }) }) diff --git a/app/src/organisms/ProtocolSetupParameters/index.tsx b/app/src/organisms/ProtocolSetupParameters/index.tsx index 1312844b2ab..7326a506895 100644 --- a/app/src/organisms/ProtocolSetupParameters/index.tsx +++ b/app/src/organisms/ProtocolSetupParameters/index.tsx @@ -1,7 +1,11 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' import { useHistory } from 'react-router-dom' -import { useCreateRunMutation, useHost } from '@opentrons/react-api-client' +import { + useCreateProtocolAnalysisMutation, + useCreateRunMutation, + useHost, +} from '@opentrons/react-api-client' import { useQueryClient } from 'react-query' import { ALIGN_CENTER, @@ -12,159 +16,18 @@ import { import { formatRunTimeParameterValue } from '@opentrons/shared-data' import { ProtocolSetupStep } from '../../pages/ProtocolSetup' +import { getRunTimeParameterValuesForRun } from '../Devices/utils' import { ChildNavigation } from '../ChildNavigation' import { ResetValuesModal } from './ResetValuesModal' import { ChooseEnum } from './ChooseEnum' +import { ChooseNumber } from './ChooseNumber' -import type { RunTimeParameter } from '@opentrons/shared-data' +import type { NumberParameter, RunTimeParameter } from '@opentrons/shared-data' import type { LabwareOffsetCreateData } from '@opentrons/api-client' -export const mockData: RunTimeParameter[] = [ - { - value: false, - displayName: 'Dry Run', - variableName: 'DRYRUN', - description: 'Is this a dry or wet run? Wet is true, dry is false', - type: 'bool', - default: false, - }, - { - value: true, - displayName: 'Use Gripper', - variableName: 'USE_GRIPPER', - description: 'For using the gripper.', - type: 'bool', - default: true, - }, - { - value: true, - displayName: 'Trash Tips', - variableName: 'TIP_TRASH', - description: - 'to throw tip into the trash or to not throw tip into the trash', - type: 'bool', - default: true, - }, - { - value: true, - displayName: 'Deactivate Temperatures', - variableName: 'DEACTIVATE_TEMP', - description: 'deactivate temperature on the module', - type: 'bool', - default: true, - }, - { - value: 4, - displayName: 'Columns of Samples', - variableName: 'COLUMNS', - description: 'How many columns do you want?', - type: 'int', - min: 1, - max: 14, - default: 4, - }, - { - value: 6, - displayName: 'PCR Cycles', - variableName: 'PCR_CYCLES', - description: 'number of PCR cycles on a thermocycler', - type: 'int', - min: 1, - max: 10, - default: 6, - }, - { - value: 6.5, - displayName: 'EtoH Volume', - variableName: 'ETOH_VOLUME', - description: '70% ethanol volume', - type: 'float', - suffix: 'mL', - min: 1.5, - max: 10.0, - default: 6.5, - }, - { - value: 'none', - displayName: 'Default Module Offsets', - variableName: 'DEFAULT_OFFSETS', - description: 'default module offsets for temp, H-S, and none', - type: 'str', - choices: [ - { - displayName: 'No offsets', - value: 'none', - }, - { - displayName: 'temp offset', - value: '1', - }, - { - displayName: 'heater-shaker offset', - value: '2', - }, - ], - default: 'none', - }, - { - value: 'left', - displayName: 'pipette mount', - variableName: 'mont', - description: 'pipette mount', - type: 'str', - choices: [ - { - displayName: 'Left', - value: 'left', - }, - { - displayName: 'Right', - value: 'right', - }, - ], - default: 'left', - }, - { - value: 'flex', - displayName: 'short test case', - variableName: 'short 2 options', - description: 'this play 2 short options', - type: 'str', - choices: [ - { - displayName: 'OT-2', - value: 'ot2', - }, - { - displayName: 'Flex', - value: 'flex', - }, - ], - default: 'flex', - }, - { - value: 'flex', - displayName: 'long test case', - variableName: 'long 2 options', - description: 'this play 2 long options', - type: 'str', - choices: [ - { - displayName: 'I am kind of long text version', - value: 'ot2', - }, - { - displayName: 'I am kind of long text version. Today is 3/15', - value: 'flex', - }, - ], - default: 'flex', - }, -] - interface ProtocolSetupParametersProps { protocolId: string - runTimeParameters?: RunTimeParameter[] + runTimeParameters: RunTimeParameter[] labwareOffsets?: LabwareOffsetCreateData[] } @@ -181,23 +44,29 @@ export function ProtocolSetupParameters({ chooseValueScreen, setChooseValueScreen, ] = React.useState(null) + const [ + showNumericalInputScreen, + setShowNumericalInputScreen, + ] = React.useState(null) const [resetValuesModal, showResetValuesModal] = React.useState( false ) - - // todo (nd:04/01/2024): remove mock and look at runTimeParameters prop - // const parameters = runTimeParameters ?? [] - const parameters = runTimeParameters ?? mockData + const [startSetup, setStartSetup] = React.useState(false) const [ runTimeParametersOverrides, setRunTimeParametersOverrides, - ] = React.useState(parameters) + ] = React.useState( + // present defaults rather than last-set value + runTimeParameters.map(param => { + return { ...param, value: param.default } + }) + ) const updateParameters = ( value: boolean | string | number, variableName: string ): void => { - const updatedParameters = parameters.map(parameter => { + const updatedParameters = runTimeParametersOverrides.map(parameter => { if (parameter.variableName === variableName) { return { ...parameter, value } } @@ -212,10 +81,27 @@ export function ProtocolSetupParameters({ setChooseValueScreen(updatedParameter) } } + if ( + showNumericalInputScreen && + showNumericalInputScreen.variableName === variableName + ) { + const updatedParameter = updatedParameters.find( + parameter => parameter.variableName === variableName + ) + if (updatedParameter != null) { + setShowNumericalInputScreen(updatedParameter as NumberParameter) + } + } } - // TODO(jr, 3/20/24): modify useCreateRunMutation to take in optional run time parameters - // newRunTimeParameters will be the param to plug in! + const runTimeParameterValues = getRunTimeParameterValuesForRun( + runTimeParametersOverrides + ) + const { createProtocolAnalysis } = useCreateProtocolAnalysisMutation( + protocolId, + host + ) + const { createRun, isLoading } = useCreateRunMutation({ onSuccess: data => { queryClient @@ -226,8 +112,33 @@ export function ProtocolSetupParameters({ }, }) const handleConfirmValues = (): void => { - createRun({ protocolId, labwareOffsets }) + setStartSetup(true) + createProtocolAnalysis({ + protocolKey: protocolId, + runTimeParameterValues: runTimeParameterValues, + }) + createRun({ + protocolId, + labwareOffsets, + runTimeParameterValues: getRunTimeParameterValuesForRun( + runTimeParametersOverrides + ), + }) + } + + const handleSetParameter = (parameter: RunTimeParameter): void => { + if ('choices' in parameter) { + setChooseValueScreen(parameter) + } else if (parameter.type === 'bool') { + updateParameters(!parameter.value, parameter.variableName) + } else if (parameter.type === 'int' || parameter.type === 'float') { + setShowNumericalInputScreen(parameter) + } else { + // bad param + console.log('error') + } } + let children = ( <> history.goBack()} onClickButton={handleConfirmValues} buttonText={t('confirm_values')} - iconName={isLoading ? 'ot-spinner' : undefined} + iconName={isLoading || startSetup ? 'ot-spinner' : undefined} iconPlacement="startIcon" secondaryButtonProps={{ buttonType: 'tertiaryLowLight', - buttonText: t('restore_default'), + buttonText: t('restore_defaults'), + disabled: isLoading || startSetup, onClick: () => showResetValuesModal(true), }} /> @@ -249,6 +161,7 @@ export function ProtocolSetupParameters({ flexDirection={DIRECTION_COLUMN} gridGap={SPACING.spacing8} paddingX={SPACING.spacing40} + paddingBottom={SPACING.spacing40} > {runTimeParametersOverrides.map((parameter, index) => { return ( @@ -257,11 +170,7 @@ export function ProtocolSetupParameters({ hasIcon={!(parameter.type === 'bool')} status="general" title={parameter.displayName} - onClickSetupStep={() => - parameter.type === 'bool' - ? updateParameters(!parameter.value, parameter.variableName) - : setChooseValueScreen(parameter) - } + onClickSetupStep={() => handleSetParameter(parameter)} detail={formatRunTimeParameterValue(parameter, t)} description={parameter.description} fontSize="h4" @@ -272,7 +181,7 @@ export function ProtocolSetupParameters({
) - if (chooseValueScreen != null && chooseValueScreen.type === 'str') { + if (chooseValueScreen != null) { children = ( setChooseValueScreen(null)} @@ -282,7 +191,15 @@ export function ProtocolSetupParameters({ /> ) } - // TODO(jr, 4/1/24): add the int/float component + if (showNumericalInputScreen != null) { + children = ( + setShowNumericalInputScreen(null)} + parameter={showNumericalInputScreen} + setParameter={updateParameters} + /> + ) + } return ( <> diff --git a/app/src/organisms/ProtocolUpload/hooks/__tests__/useCloneRun.test.tsx b/app/src/organisms/ProtocolUpload/hooks/__tests__/useCloneRun.test.tsx index af388d30930..40726be91bf 100644 --- a/app/src/organisms/ProtocolUpload/hooks/__tests__/useCloneRun.test.tsx +++ b/app/src/organisms/ProtocolUpload/hooks/__tests__/useCloneRun.test.tsx @@ -4,7 +4,11 @@ import { renderHook } from '@testing-library/react' import { QueryClient, QueryClientProvider } from 'react-query' import { describe, it, beforeEach, afterEach, vi, expect } from 'vitest' -import { useHost, useCreateRunMutation } from '@opentrons/react-api-client' +import { + useHost, + useCreateRunMutation, + useCreateProtocolAnalysisMutation, +} from '@opentrons/react-api-client' import { useCloneRun } from '../useCloneRun' import { useNotifyRunQuery } from '../../../../resources/runs' @@ -30,13 +34,16 @@ describe('useCloneRun hook', () => { id: RUN_ID, protocolId: 'protocolId', labwareOffsets: 'someOffset', - runTimeParameterValues: 'someRtp', + runTimeParameters: [], }, }, } as any) when(vi.mocked(useCreateRunMutation)) .calledWith(expect.anything()) .thenReturn({ createRun: vi.fn() } as any) + vi.mocked(useCreateProtocolAnalysisMutation).mockReturnValue({ + createProtocolAnalysis: vi.fn(), + } as any) const queryClient = new QueryClient() const clientProvider: React.FunctionComponent<{ @@ -61,7 +68,7 @@ describe('useCloneRun hook', () => { expect(mockCreateRun).toHaveBeenCalledWith({ protocolId: 'protocolId', labwareOffsets: 'someOffset', - runTimeParameterValues: 'someRtp', + runTimeParameterValues: {}, }) }) }) diff --git a/app/src/organisms/ProtocolUpload/hooks/useCloneRun.ts b/app/src/organisms/ProtocolUpload/hooks/useCloneRun.ts index 0858544d93c..fe6e3ab3649 100644 --- a/app/src/organisms/ProtocolUpload/hooks/useCloneRun.ts +++ b/app/src/organisms/ProtocolUpload/hooks/useCloneRun.ts @@ -1,10 +1,13 @@ import { useQueryClient } from 'react-query' -import { useHost, useCreateRunMutation } from '@opentrons/react-api-client' - +import { + useHost, + useCreateRunMutation, + useCreateProtocolAnalysisMutation, +} from '@opentrons/react-api-client' import { useNotifyRunQuery } from '../../../resources/runs' -import type { Run } from '@opentrons/api-client' +import type { Run, RunTimeParameterCreateData } from '@opentrons/api-client' interface UseCloneRunResult { cloneRun: () => void @@ -13,28 +16,45 @@ interface UseCloneRunResult { export function useCloneRun( runId: string | null, - onSuccessCallback?: (createRunResponse: Run) => unknown + onSuccessCallback?: (createRunResponse: Run) => unknown, + triggerAnalysis: boolean = false ): UseCloneRunResult { const host = useHost() const queryClient = useQueryClient() const { data: runRecord } = useNotifyRunQuery(runId) + const protocolKey = runRecord?.data.protocolId ?? null + const { createRun, isLoading } = useCreateRunMutation({ onSuccess: response => { - queryClient - .invalidateQueries([host, 'runs']) - .catch((e: Error) => - console.error(`error invalidating runs query: ${e.message}`) - ) + const invalidateRuns = queryClient.invalidateQueries([host, 'runs']) + const invalidateProtocols = queryClient.invalidateQueries([ + host, + 'protocols', + protocolKey, + ]) + Promise.all([invalidateRuns, invalidateProtocols]).catch((e: Error) => + console.error(`error invalidating runs query: ${e.message}`) + ) if (onSuccessCallback != null) onSuccessCallback(response) }, }) + const { createProtocolAnalysis } = useCreateProtocolAnalysisMutation( + protocolKey, + host + ) const cloneRun = (): void => { if (runRecord != null) { - const { - protocolId, - labwareOffsets, - runTimeParameterValues, - } = runRecord.data + const { protocolId, labwareOffsets, runTimeParameters } = runRecord.data + const runTimeParameterValues = runTimeParameters.reduce( + (acc, param) => + param.value !== param.default + ? { ...acc, [param.variableName]: param.value } + : acc, + {} + ) + if (triggerAnalysis && protocolKey != null) { + createProtocolAnalysis({ protocolKey, runTimeParameterValues }) + } createRun({ protocolId, labwareOffsets, runTimeParameterValues }) } else { console.info('failed to clone run record, source run record not found') diff --git a/app/src/organisms/ProtocolsLanding/ProtocolCard.tsx b/app/src/organisms/ProtocolsLanding/ProtocolCard.tsx index 932e7e0086c..89658e81ef4 100644 --- a/app/src/organisms/ProtocolsLanding/ProtocolCard.tsx +++ b/app/src/organisms/ProtocolsLanding/ProtocolCard.tsx @@ -184,8 +184,20 @@ function AnalysisInfo(props: AnalysisInfoProps): JSX.Element { size={SIZE_3} /> ), - error: , - stale: , + error: ( + + ), + stale: ( + + ), complete: mostRecentAnalysis != null ? ( diff --git a/app/src/organisms/QuickTransferFlow/ConfirmExitModal.tsx b/app/src/organisms/QuickTransferFlow/ConfirmExitModal.tsx new file mode 100644 index 00000000000..817e9fe9a1d --- /dev/null +++ b/app/src/organisms/QuickTransferFlow/ConfirmExitModal.tsx @@ -0,0 +1,54 @@ +import * as React from 'react' +import { useTranslation } from 'react-i18next' +import { + SPACING, + COLORS, + StyledText, + Flex, + DIRECTION_COLUMN, + TYPOGRAPHY, +} from '@opentrons/components' +import { Modal } from '../../molecules/Modal' +import { SmallButton } from '../../atoms/buttons' + +interface ConfirmExitModalProps { + confirmExit: () => void + cancelExit: () => void +} + +export const ConfirmExitModal = (props: ConfirmExitModalProps): JSX.Element => { + const { i18n, t } = useTranslation(['quick_transfer', 'shared']) + + return ( + + + + {t('lose_all_progress')} + + + + + + + + ) +} diff --git a/app/src/organisms/QuickTransferFlow/CreateNewTransfer.tsx b/app/src/organisms/QuickTransferFlow/CreateNewTransfer.tsx new file mode 100644 index 00000000000..21689fa2ceb --- /dev/null +++ b/app/src/organisms/QuickTransferFlow/CreateNewTransfer.tsx @@ -0,0 +1,76 @@ +import * as React from 'react' +import { useTranslation, Trans } from 'react-i18next' + +import { + Flex, + SPACING, + StyledText, + DeckConfigurator, + TYPOGRAPHY, + DIRECTION_COLUMN, +} from '@opentrons/components' + +import { SmallButton } from '../../atoms/buttons' +import { ChildNavigation } from '../ChildNavigation' +import { useNotifyDeckConfigurationQuery } from '../../resources/deck_configuration' + +interface CreateNewTransferProps { + onNext: () => void + exitButtonProps: React.ComponentProps +} + +export function CreateNewTransfer(props: CreateNewTransferProps): JSX.Element { + const { i18n, t } = useTranslation(['quick_transfer', 'shared']) + const deckConfig = useNotifyDeckConfigurationQuery().data ?? [] + return ( + + + + + + + ), + }} + /> + + + {}} + handleClickRemove={() => {}} + additionalStaticFixtures={[ + { location: 'cutoutB2', label: t('tip_rack') }, + { location: 'cutoutC2', label: t('labware') }, + { location: 'cutoutD2', label: t('labware') }, + ]} + /> + + + + + ) +} diff --git a/app/src/organisms/QuickTransferFlow/SelectDestLabware.tsx b/app/src/organisms/QuickTransferFlow/SelectDestLabware.tsx new file mode 100644 index 00000000000..d9ec6e99189 --- /dev/null +++ b/app/src/organisms/QuickTransferFlow/SelectDestLabware.tsx @@ -0,0 +1,147 @@ +import * as React from 'react' +import { useTranslation } from 'react-i18next' +import { + Flex, + SPACING, + DIRECTION_COLUMN, + DIRECTION_ROW, + COLORS, + POSITION_FIXED, + ALIGN_CENTER, +} from '@opentrons/components' + +import { SmallButton, LargeButton, TabbedButton } from '../../atoms/buttons' +import { ChildNavigation } from '../ChildNavigation' +import { getCompatibleLabwareByCategory } from './utils' + +import type { LabwareDefinition2 } from '@opentrons/shared-data' +import type { + QuickTransferSetupState, + QuickTransferWizardAction, +} from './types' +import { LabwareFilter } from '../../pages/Labware/types' + +interface SelectDestLabwareProps { + onNext: () => void + onBack: () => void + exitButtonProps: React.ComponentProps + state: QuickTransferSetupState + dispatch: React.Dispatch +} + +export function SelectDestLabware( + props: SelectDestLabwareProps +): JSX.Element | null { + const { onNext, onBack, exitButtonProps, state, dispatch } = props + const { i18n, t } = useTranslation(['quick_transfer', 'shared']) + const labwareDisplayCategoryFilters: LabwareFilter[] = [ + 'all', + 'wellPlate', + 'reservoir', + ] + if (state.pipette?.channels === 1) { + labwareDisplayCategoryFilters.push('tubeRack') + } + const [selectedCategory, setSelectedCategory] = React.useState( + 'all' + ) + const [selectedLabware, setSelectedLabware] = React.useState< + LabwareDefinition2 | 'source' | undefined + >(state.destination) + + if (state.pipette == null) return null + + const compatibleLabwareDefinitions = getCompatibleLabwareByCategory( + state.pipette.channels, + selectedCategory + ) + + const handleClickNext = (): void => { + // the button will be disabled if this values is null + if (selectedLabware != null) { + dispatch({ + type: 'SET_DEST_LABWARE', + labware: selectedLabware, + }) + onNext() + } + } + return ( + + + + + {labwareDisplayCategoryFilters.map(category => ( + setSelectedCategory(category)} + height={SPACING.spacing60} + > + {t(category)} + + ))} + + + {selectedCategory === 'all' && state?.source != null ? ( + { + setSelectedLabware('source') + }} + buttonText={t('source_labware')} + subtext={state.source.metadata.displayName} + /> + ) : null} + {compatibleLabwareDefinitions?.map(definition => { + return definition.metadata.displayName != null ? ( + { + setSelectedLabware(definition) + }} + buttonText={definition.metadata.displayName} + /> + ) : null + })} + + + + ) +} diff --git a/app/src/organisms/QuickTransferFlow/SelectDestWells.tsx b/app/src/organisms/QuickTransferFlow/SelectDestWells.tsx new file mode 100644 index 00000000000..39ef17cffe9 --- /dev/null +++ b/app/src/organisms/QuickTransferFlow/SelectDestWells.tsx @@ -0,0 +1,59 @@ +import * as React from 'react' +import { useTranslation } from 'react-i18next' +import { Flex, SPACING } from '@opentrons/components' + +import { SmallButton } from '../../atoms/buttons' +import { ChildNavigation } from '../ChildNavigation' + +import type { + QuickTransferSetupState, + QuickTransferWizardAction, +} from './types' + +interface SelectDestWellsProps { + onNext: () => void + onBack: () => void + exitButtonProps: React.ComponentProps + state: QuickTransferSetupState + dispatch: React.Dispatch +} + +export function SelectDestWells(props: SelectDestWellsProps): JSX.Element { + const { onNext, onBack, exitButtonProps, state, dispatch } = props + const { i18n, t } = useTranslation(['quick_transfer', 'shared']) + + const handleClickNext = (): void => { + // until well selection is implemented, select all wells and proceed to the next step + if (state.destination === 'source' && state.source != null) { + dispatch({ + type: 'SET_DEST_WELLS', + wells: Object.keys(state.source.wells), + }) + } else if (state.destination !== 'source' && state.destination != null) { + dispatch({ + type: 'SET_DEST_WELLS', + wells: Object.keys(state.destination.wells), + }) + } + onNext() + } + return ( + + + + TODO: Add destination well selection deck map + + + ) +} diff --git a/app/src/organisms/QuickTransferFlow/SelectPipette.tsx b/app/src/organisms/QuickTransferFlow/SelectPipette.tsx new file mode 100644 index 00000000000..6ef31157fdf --- /dev/null +++ b/app/src/organisms/QuickTransferFlow/SelectPipette.tsx @@ -0,0 +1,117 @@ +import * as React from 'react' +import { useTranslation } from 'react-i18next' +import { + Flex, + SPACING, + StyledText, + TYPOGRAPHY, + DIRECTION_COLUMN, +} from '@opentrons/components' +import { useInstrumentsQuery } from '@opentrons/react-api-client' +import { getPipetteSpecsV2, RIGHT, LEFT } from '@opentrons/shared-data' +import { SmallButton, LargeButton } from '../../atoms/buttons' +import { ChildNavigation } from '../ChildNavigation' + +import type { PipetteData, Mount } from '@opentrons/api-client' +import type { + QuickTransferSetupState, + QuickTransferWizardAction, +} from './types' + +interface SelectPipetteProps { + onNext: () => void + onBack: () => void + exitButtonProps: React.ComponentProps + state: QuickTransferSetupState + dispatch: React.Dispatch +} + +export function SelectPipette(props: SelectPipetteProps): JSX.Element { + const { onNext, onBack, exitButtonProps, state, dispatch } = props + const { i18n, t } = useTranslation(['quick_transfer', 'shared']) + const { data: attachedInstruments } = useInstrumentsQuery() + + const leftPipette = attachedInstruments?.data.find( + (i): i is PipetteData => i.ok && i.mount === LEFT + ) + const leftPipetteSpecs = + leftPipette != null ? getPipetteSpecsV2(leftPipette.instrumentModel) : null + + const rightPipette = attachedInstruments?.data.find( + (i): i is PipetteData => i.ok && i.mount === RIGHT + ) + const rightPipetteSpecs = + rightPipette != null + ? getPipetteSpecsV2(rightPipette.instrumentModel) + : null + + // automatically select 96 channel if it is attached + const [selectedPipette, setSelectedPipette] = React.useState< + Mount | undefined + >(leftPipetteSpecs?.channels === 96 ? LEFT : state.mount) + + const handleClickNext = (): void => { + const selectedPipetteSpecs = + selectedPipette === LEFT ? leftPipetteSpecs : rightPipetteSpecs + + // the button will be disabled if these values are null + if (selectedPipette != null && selectedPipetteSpecs != null) { + dispatch({ + type: 'SELECT_PIPETTE', + pipette: selectedPipetteSpecs, + mount: selectedPipette, + }) + onNext() + } + } + return ( + + + + + {t('pipette_currently_attached')} + + {leftPipetteSpecs != null ? ( + { + setSelectedPipette(LEFT) + }} + buttonText={ + leftPipetteSpecs.channels === 96 + ? t('both_mounts') + : t('left_mount') + } + subtext={leftPipetteSpecs.displayName} + /> + ) : null} + {rightPipetteSpecs != null ? ( + { + setSelectedPipette(RIGHT) + }} + buttonText={t('right_mount')} + subtext={rightPipetteSpecs.displayName} + /> + ) : null} + + + ) +} diff --git a/app/src/organisms/QuickTransferFlow/SelectSourceLabware.tsx b/app/src/organisms/QuickTransferFlow/SelectSourceLabware.tsx new file mode 100644 index 00000000000..5c2889b91f7 --- /dev/null +++ b/app/src/organisms/QuickTransferFlow/SelectSourceLabware.tsx @@ -0,0 +1,135 @@ +import * as React from 'react' +import { useTranslation } from 'react-i18next' +import { + Flex, + SPACING, + DIRECTION_COLUMN, + DIRECTION_ROW, + COLORS, + POSITION_FIXED, + ALIGN_CENTER, +} from '@opentrons/components' + +import { SmallButton, LargeButton, TabbedButton } from '../../atoms/buttons' +import { ChildNavigation } from '../ChildNavigation' +import { getCompatibleLabwareByCategory } from './utils' + +import type { LabwareDefinition2 } from '@opentrons/shared-data' +import type { + QuickTransferSetupState, + QuickTransferWizardAction, +} from './types' +import { LabwareFilter } from '../../pages/Labware/types' + +interface SelectSourceLabwareProps { + onNext: () => void + onBack: () => void + exitButtonProps: React.ComponentProps + state: QuickTransferSetupState + dispatch: React.Dispatch +} + +export function SelectSourceLabware( + props: SelectSourceLabwareProps +): JSX.Element | null { + const { onNext, onBack, exitButtonProps, state, dispatch } = props + const { i18n, t } = useTranslation(['quick_transfer', 'shared']) + const labwareDisplayCategoryFilters: LabwareFilter[] = [ + 'all', + 'wellPlate', + 'reservoir', + ] + if (state.pipette?.channels === 1) { + labwareDisplayCategoryFilters.push('tubeRack') + } + const [selectedCategory, setSelectedCategory] = React.useState( + 'all' + ) + + const [selectedLabware, setSelectedLabware] = React.useState< + LabwareDefinition2 | undefined + >(state.source) + + if (state.pipette == null) return null + + const compatibleLabwareDefinitions = getCompatibleLabwareByCategory( + state.pipette.channels, + selectedCategory + ) + + const handleClickNext = (): void => { + // the button will be disabled if this values is null + if (selectedLabware != null) { + dispatch({ + type: 'SET_SOURCE_LABWARE', + labware: selectedLabware, + }) + onNext() + } + } + return ( + + + + + {labwareDisplayCategoryFilters.map(category => ( + setSelectedCategory(category)} + height={SPACING.spacing60} + > + {t(category)} + + ))} + + + {compatibleLabwareDefinitions?.map(definition => { + return definition.metadata.displayName != null ? ( + { + setSelectedLabware(definition) + }} + buttonText={definition.metadata.displayName} + /> + ) : null + })} + + + + ) +} diff --git a/app/src/organisms/QuickTransferFlow/SelectSourceWells.tsx b/app/src/organisms/QuickTransferFlow/SelectSourceWells.tsx new file mode 100644 index 00000000000..1cdc2b75595 --- /dev/null +++ b/app/src/organisms/QuickTransferFlow/SelectSourceWells.tsx @@ -0,0 +1,54 @@ +import * as React from 'react' +import { useTranslation } from 'react-i18next' +import { Flex, SPACING } from '@opentrons/components' + +import { SmallButton } from '../../atoms/buttons' +import { ChildNavigation } from '../ChildNavigation' + +import type { + QuickTransferSetupState, + QuickTransferWizardAction, +} from './types' + +interface SelectSourceWellsProps { + onNext: () => void + onBack: () => void + exitButtonProps: React.ComponentProps + state: QuickTransferSetupState + dispatch: React.Dispatch +} + +export function SelectSourceWells(props: SelectSourceWellsProps): JSX.Element { + const { onNext, onBack, exitButtonProps, state, dispatch } = props + const { i18n, t } = useTranslation(['quick_transfer', 'shared']) + + const handleClickNext = (): void => { + // until well selection is implemented, select all wells and proceed to the next step + if (state.source?.wells != null) { + dispatch({ + type: 'SET_SOURCE_WELLS', + wells: Object.keys(state.source.wells), + }) + onNext() + } + } + return ( + + + + TODO: Add source well selection deck map + + + ) +} diff --git a/app/src/organisms/QuickTransferFlow/SelectTipRack.tsx b/app/src/organisms/QuickTransferFlow/SelectTipRack.tsx new file mode 100644 index 00000000000..ec5e3cad0e0 --- /dev/null +++ b/app/src/organisms/QuickTransferFlow/SelectTipRack.tsx @@ -0,0 +1,81 @@ +import * as React from 'react' +import { useTranslation } from 'react-i18next' +import { Flex, SPACING, DIRECTION_COLUMN } from '@opentrons/components' +import { getAllDefinitions } from '@opentrons/shared-data' +import { SmallButton, LargeButton } from '../../atoms/buttons' +import { ChildNavigation } from '../ChildNavigation' + +import type { LabwareDefinition2 } from '@opentrons/shared-data' +import type { + QuickTransferSetupState, + QuickTransferWizardAction, +} from './types' + +interface SelectTipRackProps { + onNext: () => void + onBack: () => void + exitButtonProps: React.ComponentProps + state: QuickTransferSetupState + dispatch: React.Dispatch +} + +export function SelectTipRack(props: SelectTipRackProps): JSX.Element { + const { onNext, onBack, exitButtonProps, state, dispatch } = props + const { i18n, t } = useTranslation(['quick_transfer', 'shared']) + + const allLabwareDefinitionsByUri = getAllDefinitions() + const selectedPipetteDefaultTipracks = + state.pipette?.liquids.default.defaultTipracks ?? [] + + const [selectedTipRack, setSelectedTipRack] = React.useState< + LabwareDefinition2 | undefined + >(state.tipRack) + + const handleClickNext = (): void => { + // the button will be disabled if this values is null + if (selectedTipRack != null) { + dispatch({ + type: 'SELECT_TIP_RACK', + tipRack: selectedTipRack, + }) + onNext() + } + } + return ( + + + + {selectedPipetteDefaultTipracks.map(tipRack => { + const tipRackDef = allLabwareDefinitionsByUri[tipRack] + + return tipRackDef != null ? ( + { + setSelectedTipRack(tipRackDef) + }} + buttonText={tipRackDef.metadata.displayName} + /> + ) : null + })} + + + ) +} diff --git a/app/src/organisms/QuickTransferFlow/VolumeEntry.tsx b/app/src/organisms/QuickTransferFlow/VolumeEntry.tsx new file mode 100644 index 00000000000..4c40eb7e048 --- /dev/null +++ b/app/src/organisms/QuickTransferFlow/VolumeEntry.tsx @@ -0,0 +1,127 @@ +import * as React from 'react' +import { useTranslation } from 'react-i18next' +import { + Flex, + SPACING, + DIRECTION_COLUMN, + ALIGN_CENTER, +} from '@opentrons/components' + +import { SmallButton } from '../../atoms/buttons' +import { ChildNavigation } from '../ChildNavigation' +import { InputField } from '../../atoms/InputField' +import { NumericalKeyboard } from '../../atoms/SoftwareKeyboard' +import { getVolumeLimits } from './utils' + +import type { + QuickTransferSetupState, + QuickTransferWizardAction, +} from './types' + +interface VolumeEntryProps { + onNext: () => void + onBack: () => void + exitButtonProps: React.ComponentProps + state: QuickTransferSetupState + dispatch: React.Dispatch +} + +export function VolumeEntry(props: VolumeEntryProps): JSX.Element { + const { onNext, onBack, exitButtonProps, state, dispatch } = props + const { i18n, t } = useTranslation(['quick_transfer', 'shared']) + const keyboardRef = React.useRef(null) + + const [volume, setVolume] = React.useState( + state.volume ? state.volume.toString() : '' + ) + const volumeRange = getVolumeLimits(state) + let headerCopy = t('set_transfer_volume') + let textEntryCopy = t('volume_per_well') + if ( + state.sourceWells != null && + state.destinationWells != null && + state.sourceWells.length > state.destinationWells?.length + ) { + headerCopy = t('set_aspirate_volume') + textEntryCopy = t('aspirate_volume') + } else if ( + state.sourceWells != null && + state.destinationWells != null && + state.sourceWells.length < state.destinationWells.length + ) { + headerCopy = t('set_dispense_volume') + textEntryCopy = t('dispense_volume') + } + + const volumeAsNumber = Number(volume) + + const handleClickNext = (): void => { + // the button will be disabled if this values is null + if (volumeAsNumber != null) { + dispatch({ + type: 'SET_VOLUME', + volume: volumeAsNumber, + }) + onNext() + } + } + + const error = + volume !== '' && + (volumeAsNumber < volumeRange.min || volumeAsNumber > volumeRange.max) + ? t(`value_out_of_range`, { + min: volumeRange.min, + max: volumeRange.max, + }) + : null + + return ( + + + + + + + + setVolume(e)} + /> + + + + ) +} diff --git a/app/src/organisms/QuickTransferFlow/__tests__/ConfirmExitModal.test.tsx b/app/src/organisms/QuickTransferFlow/__tests__/ConfirmExitModal.test.tsx new file mode 100644 index 00000000000..f1e3681a93a --- /dev/null +++ b/app/src/organisms/QuickTransferFlow/__tests__/ConfirmExitModal.test.tsx @@ -0,0 +1,42 @@ +import * as React from 'react' +import { fireEvent, screen } from '@testing-library/react' +import { describe, it, expect, afterEach, vi, beforeEach } from 'vitest' + +import { renderWithProviders } from '../../../__testing-utils__' +import { i18n } from '../../../i18n' +import { ConfirmExitModal } from '../ConfirmExitModal' + +const render = (props: React.ComponentProps) => { + return renderWithProviders(, { + i18nInstance: i18n, + }) +} + +describe('ConfirmExitModal', () => { + let props: React.ComponentProps + + beforeEach(() => { + props = { + confirmExit: vi.fn(), + cancelExit: vi.fn(), + } + }) + afterEach(() => { + vi.resetAllMocks() + }) + + it('renders the create new transfer screen and header', () => { + render(props) + screen.getByText('Exit quick transfer?') + screen.getByText('You will lose all progress on this quick transfer.') + }) + it('renders exit and cancel buttons and they work as expected', () => { + render(props) + const cancelBtn = screen.getByText('Cancel') + fireEvent.click(cancelBtn) + expect(props.cancelExit).toHaveBeenCalled() + const deleteBtn = screen.getByText('Delete') + fireEvent.click(deleteBtn) + expect(props.confirmExit).toHaveBeenCalled() + }) +}) diff --git a/app/src/organisms/QuickTransferFlow/__tests__/CreateNewTransfer.test.tsx b/app/src/organisms/QuickTransferFlow/__tests__/CreateNewTransfer.test.tsx new file mode 100644 index 00000000000..abeba9a2b1d --- /dev/null +++ b/app/src/organisms/QuickTransferFlow/__tests__/CreateNewTransfer.test.tsx @@ -0,0 +1,62 @@ +import * as React from 'react' +import { fireEvent, screen } from '@testing-library/react' +import { describe, it, expect, afterEach, vi, beforeEach } from 'vitest' +import { DeckConfigurator } from '@opentrons/components' + +import { renderWithProviders } from '../../../__testing-utils__' +import { i18n } from '../../../i18n' +import { CreateNewTransfer } from '../CreateNewTransfer' + +import type * as OpentronsComponents from '@opentrons/components' + +vi.mock('@opentrons/components', async importOriginal => { + const actual = await importOriginal() + return { + ...actual, + DeckConfigurator: vi.fn(), + } +}) +const render = (props: React.ComponentProps) => { + return renderWithProviders(, { + i18nInstance: i18n, + }) +} + +describe('CreateNewTransfer', () => { + let props: React.ComponentProps + + beforeEach(() => { + props = { + onNext: vi.fn(), + exitButtonProps: { + buttonType: 'tertiaryLowLight', + buttonText: 'Exit', + onClick: vi.fn(), + }, + } + }) + afterEach(() => { + vi.resetAllMocks() + }) + + it('renders the create new transfer screen and header', () => { + render(props) + screen.getByText('Create new quick transfer') + screen.getByText( + 'Quick transfers use deck slots B2-D2. These slots hold a tip rack, a source labware, and a destination labware.' + ) + screen.getByText( + 'Make sure that your deck configuration is up to date to avoid collisions.' + ) + expect(vi.mocked(DeckConfigurator)).toHaveBeenCalled() + }) + it('renders exit and continue buttons and they work as expected', () => { + render(props) + const exitBtn = screen.getByText('Exit') + fireEvent.click(exitBtn) + expect(props.exitButtonProps.onClick).toHaveBeenCalled() + const continueBtn = screen.getByText('Continue') + fireEvent.click(continueBtn) + expect(props.onNext).toHaveBeenCalled() + }) +}) diff --git a/app/src/organisms/QuickTransferFlow/__tests__/SelectDestLabware.test.tsx b/app/src/organisms/QuickTransferFlow/__tests__/SelectDestLabware.test.tsx new file mode 100644 index 00000000000..a2d2430c268 --- /dev/null +++ b/app/src/organisms/QuickTransferFlow/__tests__/SelectDestLabware.test.tsx @@ -0,0 +1,116 @@ +import * as React from 'react' +import { fireEvent, screen } from '@testing-library/react' +import { describe, it, expect, afterEach, vi, beforeEach } from 'vitest' + +import { renderWithProviders } from '../../../__testing-utils__' +import { i18n } from '../../../i18n' +import { SelectDestLabware } from '../SelectDestLabware' + +vi.mock('@opentrons/react-api-client') +const render = (props: React.ComponentProps) => { + return renderWithProviders(, { + i18nInstance: i18n, + }) +} + +describe('SelectDestLabware', () => { + let props: React.ComponentProps + + beforeEach(() => { + props = { + onNext: vi.fn(), + onBack: vi.fn(), + exitButtonProps: { + buttonType: 'tertiaryLowLight', + buttonText: 'Exit', + onClick: vi.fn(), + }, + state: { + mount: 'left', + pipette: { + channels: 1, + } as any, + }, + dispatch: vi.fn(), + } + }) + afterEach(() => { + vi.resetAllMocks() + }) + + it('renders the select destination labware screen, header, and exit button', () => { + render(props) + screen.getByText('Select destination labware') + const exitBtn = screen.getByText('Exit') + fireEvent.click(exitBtn) + expect(props.exitButtonProps.onClick).toHaveBeenCalled() + }) + + it('renders continue button and it is disabled if no labware is selected', () => { + render(props) + screen.getByText('Continue') + const continueBtn = screen.getByTestId('ChildNavigation_Primary_Button') + expect(continueBtn).toBeDisabled() + }) + + it('selects labware by default if there is one in state, button will be enabled', () => { + render({ + ...props, + state: { + pipette: { + channels: 1, + } as any, + destination: { + metadata: { + displayName: 'destination labware name', + }, + } as any, + }, + }) + const continueBtn = screen.getByTestId('ChildNavigation_Primary_Button') + expect(continueBtn).toBeEnabled() + fireEvent.click(continueBtn) + expect(props.onNext).toHaveBeenCalled() + expect(props.dispatch).toHaveBeenCalled() + }) + + it('renders all categories for a single channel pipette', () => { + render(props) + screen.getByText('All labware') + screen.getByText('Well plates') + screen.getByText('Reservoirs') + screen.getByText('Tube racks') + }) + + it.fails('does not render tube rack tab for multi channel pipette', () => { + render({ ...props, state: { pipette: { channels: 8 } as any } }) + screen.getByText('Tube racks') + }) + + it('renders the source labware as the first option', () => { + render({ + ...props, + state: { + pipette: { channels: 8 } as any, + source: { metadata: { displayName: 'source labware name' } } as any, + }, + }) + render(props) + screen.getByText('Source labware in D2') + screen.getByText('source labware name') + }) + it('enables continue button if you select a labware', () => { + render({ + ...props, + state: { + pipette: { channels: 8 } as any, + source: { metadata: { displayName: 'source labware name' } } as any, + }, + }) + const continueBtn = screen.getByTestId('ChildNavigation_Primary_Button') + expect(continueBtn).toBeDisabled() + const sourceLabware = screen.getByText('Source labware in D2') + fireEvent.click(sourceLabware) + expect(continueBtn).toBeEnabled() + }) +}) diff --git a/app/src/organisms/QuickTransferFlow/__tests__/SelectPipette.test.tsx b/app/src/organisms/QuickTransferFlow/__tests__/SelectPipette.test.tsx new file mode 100644 index 00000000000..2d6faa6ffa7 --- /dev/null +++ b/app/src/organisms/QuickTransferFlow/__tests__/SelectPipette.test.tsx @@ -0,0 +1,126 @@ +import * as React from 'react' +import { fireEvent, screen } from '@testing-library/react' +import { describe, it, expect, afterEach, vi, beforeEach } from 'vitest' +import { useInstrumentsQuery } from '@opentrons/react-api-client' + +import { renderWithProviders } from '../../../__testing-utils__' +import { i18n } from '../../../i18n' +import { SelectPipette } from '../SelectPipette' + +vi.mock('@opentrons/react-api-client') +const render = (props: React.ComponentProps) => { + return renderWithProviders(, { + i18nInstance: i18n, + }) +} + +describe('SelectPipette', () => { + let props: React.ComponentProps + + beforeEach(() => { + props = { + onNext: vi.fn(), + onBack: vi.fn(), + exitButtonProps: { + buttonType: 'tertiaryLowLight', + buttonText: 'Exit', + onClick: vi.fn(), + }, + state: {}, + dispatch: vi.fn(), + } + vi.mocked(useInstrumentsQuery).mockReturnValue({ + data: { + data: [ + { + instrumentType: 'pipette', + mount: 'left', + ok: true, + firmwareVersion: 12, + instrumentName: 'p10_single', + instrumentModel: 'p1000_multi_v3.4', + data: {}, + } as any, + { + instrumentType: 'pipette', + mount: 'right', + ok: true, + firmwareVersion: 12, + instrumentName: 'p10_single', + instrumentModel: 'p1000_multi_v3.4', + data: {}, + } as any, + ], + }, + } as any) + }) + afterEach(() => { + vi.resetAllMocks() + }) + + it('renders the select pipette screen, header, and exit button', () => { + render(props) + screen.getByText('Select attached pipette') + screen.getByText( + 'Quick transfer options depend on the pipettes currently attached to your robot.' + ) + const exitBtn = screen.getByText('Exit') + fireEvent.click(exitBtn) + expect(props.exitButtonProps.onClick).toHaveBeenCalled() + }) + + it('renders continue button and it is disabled if no pipette is selected', () => { + render(props) + screen.getByText('Continue') + const continueBtn = screen.getByTestId('ChildNavigation_Primary_Button') + expect(continueBtn).toBeDisabled() + }) + + it('renders both pipette buttons if there are two attached', () => { + render(props) + screen.getByText('Left Mount') + screen.getByText('Right Mount') + }) + + it('selects pipette by default if there is one in state, button will be enabled', () => { + render({ ...props, state: { mount: 'left' } }) + const continueBtn = screen.getByTestId('ChildNavigation_Primary_Button') + expect(continueBtn).toBeEnabled() + fireEvent.click(continueBtn) + expect(props.onNext).toHaveBeenCalled() + }) + + it('enables continue button if you click a pipette', () => { + render(props) + const continueBtn = screen.getByTestId('ChildNavigation_Primary_Button') + expect(continueBtn).toBeDisabled() + const leftButton = screen.getByText('Left Mount') + fireEvent.click(leftButton) + expect(continueBtn).toBeEnabled() + fireEvent.click(continueBtn) + expect(props.dispatch).toHaveBeenCalled() + expect(props.onNext).toHaveBeenCalled() + }) + + it('renders left and right button if 96 is attached and automatically selects the pipette', () => { + vi.mocked(useInstrumentsQuery).mockReturnValue({ + data: { + data: [ + { + instrumentType: 'pipette', + mount: 'left', + ok: true, + firmwareVersion: 12, + instrumentName: 'p1000_96', + instrumentModel: 'p1000_96_v1', + data: {}, + } as any, + ], + }, + } as any) + render(props) + screen.getByText('Left + Right Mount') + const continueBtn = screen.getByTestId('ChildNavigation_Primary_Button') + expect(continueBtn).toBeEnabled() + }) +}) diff --git a/app/src/organisms/QuickTransferFlow/__tests__/SelectSourceLabware.test.tsx b/app/src/organisms/QuickTransferFlow/__tests__/SelectSourceLabware.test.tsx new file mode 100644 index 00000000000..43b8c1a1e15 --- /dev/null +++ b/app/src/organisms/QuickTransferFlow/__tests__/SelectSourceLabware.test.tsx @@ -0,0 +1,101 @@ +import * as React from 'react' +import { fireEvent, screen } from '@testing-library/react' +import { describe, it, expect, afterEach, vi, beforeEach } from 'vitest' + +import { renderWithProviders } from '../../../__testing-utils__' +import { i18n } from '../../../i18n' +import { SelectSourceLabware } from '../SelectSourceLabware' + +vi.mock('@opentrons/react-api-client') +const render = (props: React.ComponentProps) => { + return renderWithProviders(, { + i18nInstance: i18n, + }) +} + +describe('SelectSourceLabware', () => { + let props: React.ComponentProps + + beforeEach(() => { + props = { + onNext: vi.fn(), + onBack: vi.fn(), + exitButtonProps: { + buttonType: 'tertiaryLowLight', + buttonText: 'Exit', + onClick: vi.fn(), + }, + state: { + mount: 'left', + pipette: { + channels: 1, + } as any, + }, + dispatch: vi.fn(), + } + }) + afterEach(() => { + vi.resetAllMocks() + }) + + it('renders the select source labware screen, header, and exit button', () => { + render(props) + screen.getByText('Select source labware') + const exitBtn = screen.getByText('Exit') + fireEvent.click(exitBtn) + expect(props.exitButtonProps.onClick).toHaveBeenCalled() + }) + + it('renders continue button and it is disabled if no labware is selected', () => { + render(props) + screen.getByText('Continue') + const continueBtn = screen.getByTestId('ChildNavigation_Primary_Button') + expect(continueBtn).toBeDisabled() + }) + + it('selects labware by default if there is one in state, button will be enabled', () => { + render({ + ...props, + state: { + pipette: { + channels: 1, + } as any, + source: { + metadata: { + displayName: 'source display name', + }, + } as any, + }, + }) + const continueBtn = screen.getByTestId('ChildNavigation_Primary_Button') + expect(continueBtn).toBeEnabled() + fireEvent.click(continueBtn) + expect(props.onNext).toHaveBeenCalled() + expect(props.dispatch).toHaveBeenCalled() + }) + + it('renders all categories for a single channel pipette', () => { + render(props) + screen.getByText('All labware') + screen.getByText('Well plates') + screen.getByText('Reservoirs') + screen.getByText('Tube racks') + }) + + it.fails('does not render tube rack tab for multi channel pipette', () => { + render({ ...props, state: { pipette: { channels: 8 } as any } }) + screen.getByText('Tube racks') + }) + + it('enables continue button if you select a labware', () => { + render(props) + const continueBtn = screen.getByTestId('ChildNavigation_Primary_Button') + expect(continueBtn).toBeDisabled() + const labwareOption = screen.getByText('Bio-Rad 384 Well Plate 50 µL') + fireEvent.click(labwareOption) + expect(continueBtn).toBeEnabled() + fireEvent.click(continueBtn) + expect(props.onNext).toHaveBeenCalled() + expect(props.dispatch).toHaveBeenCalled() + }) +}) diff --git a/app/src/organisms/QuickTransferFlow/__tests__/SelectTipRack.test.tsx b/app/src/organisms/QuickTransferFlow/__tests__/SelectTipRack.test.tsx new file mode 100644 index 00000000000..b32b3188910 --- /dev/null +++ b/app/src/organisms/QuickTransferFlow/__tests__/SelectTipRack.test.tsx @@ -0,0 +1,86 @@ +import * as React from 'react' +import { fireEvent, screen } from '@testing-library/react' +import { describe, it, expect, afterEach, vi, beforeEach } from 'vitest' + +import { renderWithProviders } from '../../../__testing-utils__' +import { i18n } from '../../../i18n' +import { SelectTipRack } from '../SelectTipRack' + +vi.mock('@opentrons/react-api-client') +const render = (props: React.ComponentProps) => { + return renderWithProviders(, { + i18nInstance: i18n, + }) +} + +describe('SelectTipRack', () => { + let props: React.ComponentProps + + beforeEach(() => { + props = { + onNext: vi.fn(), + onBack: vi.fn(), + exitButtonProps: { + buttonType: 'tertiaryLowLight', + buttonText: 'Exit', + onClick: vi.fn(), + }, + state: { + mount: 'left', + pipette: { + liquids: { + default: { + defaultTipracks: [ + 'opentrons/opentrons_flex_96_tiprack_1000ul/1', + 'opentrons/opentrons_flex_96_tiprack_200ul/1', + 'opentrons/opentrons_flex_96_tiprack_50ul/1', + 'opentrons/opentrons_flex_96_filtertiprack_1000ul/1', + 'opentrons/opentrons_flex_96_filtertiprack_200ul/1', + 'opentrons/opentrons_flex_96_filtertiprack_50ul/1', + ], + }, + }, + } as any, + }, + dispatch: vi.fn(), + } + }) + afterEach(() => { + vi.resetAllMocks() + }) + + it('renders the select tip rack screen, header, and exit button', () => { + render(props) + screen.getByText('Select tip rack') + const exitBtn = screen.getByText('Exit') + fireEvent.click(exitBtn) + expect(props.exitButtonProps.onClick).toHaveBeenCalled() + }) + + it('renders continue button and it is disabled if no tip rack is selected', () => { + render(props) + screen.getByText('Continue') + const continueBtn = screen.getByTestId('ChildNavigation_Primary_Button') + expect(continueBtn).toBeDisabled() + }) + + it('selects tip rack by default if there is one in state, button will be enabled', () => { + render({ ...props, state: { tipRack: { def: 'definition' } as any } }) + const continueBtn = screen.getByTestId('ChildNavigation_Primary_Button') + expect(continueBtn).toBeEnabled() + fireEvent.click(continueBtn) + expect(props.onNext).toHaveBeenCalled() + }) + + it('enables continue button if you click a tip rack', () => { + render(props) + const continueBtn = screen.getByTestId('ChildNavigation_Primary_Button') + expect(continueBtn).toBeDisabled() + const tipRackButton = screen.getByText('Opentrons Flex 96 Tip Rack 200 µL') + fireEvent.click(tipRackButton) + expect(continueBtn).toBeEnabled() + fireEvent.click(continueBtn) + expect(props.dispatch).toHaveBeenCalled() + expect(props.onNext).toHaveBeenCalled() + }) +}) diff --git a/app/src/organisms/QuickTransferFlow/__tests__/VolumeEntry.test.tsx b/app/src/organisms/QuickTransferFlow/__tests__/VolumeEntry.test.tsx new file mode 100644 index 00000000000..dd2bb6dae4c --- /dev/null +++ b/app/src/organisms/QuickTransferFlow/__tests__/VolumeEntry.test.tsx @@ -0,0 +1,158 @@ +import * as React from 'react' +import { fireEvent, screen } from '@testing-library/react' +import { describe, it, expect, afterEach, vi, beforeEach } from 'vitest' + +import { renderWithProviders } from '../../../__testing-utils__' +import { i18n } from '../../../i18n' +import { InputField } from '../../../atoms/InputField' +import { NumericalKeyboard } from '../../../atoms/SoftwareKeyboard' +import { getVolumeLimits } from '../utils' +import { VolumeEntry } from '../VolumeEntry' + +vi.mock('../../../atoms/InputField') +vi.mock('../../../atoms/SoftwareKeyboard') +vi.mock('../utils') + +const render = (props: React.ComponentProps) => { + return renderWithProviders(, { + i18nInstance: i18n, + }) +} + +describe('VolumeEntry', () => { + let props: React.ComponentProps + + beforeEach(() => { + props = { + onNext: vi.fn(), + onBack: vi.fn(), + exitButtonProps: { + buttonType: 'tertiaryLowLight', + buttonText: 'Exit', + onClick: vi.fn(), + }, + state: { + mount: 'left', + pipette: { + channels: 1, + } as any, + sourceWells: ['A1'], + destinationWells: ['A1'], + }, + dispatch: vi.fn(), + } + vi.mocked(getVolumeLimits).mockReturnValue({ min: 5, max: 50 }) + }) + afterEach(() => { + vi.resetAllMocks() + }) + + it('renders the volume entry screen, continue, and exit buttons', () => { + render(props) + const exitBtn = screen.getByText('Exit') + fireEvent.click(exitBtn) + expect(props.exitButtonProps.onClick).toHaveBeenCalled() + expect(vi.mocked(InputField)).toHaveBeenCalled() + expect(vi.mocked(NumericalKeyboard)).toHaveBeenCalled() + const continueBtn = screen.getByTestId('ChildNavigation_Primary_Button') + expect(continueBtn).toBeDisabled() + }) + + it('renders transfer text if there are more destination wells than source wells', () => { + render(props) + screen.getByText('Set transfer volume') + expect(vi.mocked(InputField)).toHaveBeenCalledWith( + { + title: 'Volume per well (µL)', + error: null, + readOnly: true, + type: 'text', + value: '', + }, + {} + ) + }) + + it('renders dispense text if there are more destination wells than source wells', () => { + render({ + ...props, + state: { + sourceWells: ['A1'], + destinationWells: ['A1', 'A2'], + }, + }) + render(props) + screen.getByText('Set dispense volume') + expect(vi.mocked(InputField)).toHaveBeenCalledWith( + { + title: 'Dispense volume per well (µL)', + error: null, + readOnly: true, + type: 'text', + value: '', + }, + {} + ) + }) + + it('renders aspirate text if there are more destination wells than source wells', () => { + render({ + ...props, + state: { + sourceWells: ['A1', 'A2'], + destinationWells: ['A1'], + }, + }) + render(props) + screen.getByText('Set aspirate volume') + expect(vi.mocked(InputField)).toHaveBeenCalledWith( + { + title: 'Aspirate volume per well (µL)', + error: null, + readOnly: true, + type: 'text', + value: '', + }, + {} + ) + }) + + it('calls on next and dispatch if you press continue when volume is non-null and within range', () => { + render({ + ...props, + state: { + sourceWells: ['A1', 'A2'], + destinationWells: ['A1'], + volume: 20, + }, + }) + const continueBtn = screen.getByTestId('ChildNavigation_Primary_Button') + expect(continueBtn).toBeEnabled() + fireEvent.click(continueBtn) + expect(vi.mocked(props.onNext)).toHaveBeenCalled() + expect(vi.mocked(props.dispatch)).toHaveBeenCalled() + }) + + it('displays an error and disables continue when volume is outside of range', () => { + render({ + ...props, + state: { + sourceWells: ['A1', 'A2'], + destinationWells: ['A1'], + volume: 90, + }, + }) + const continueBtn = screen.getByTestId('ChildNavigation_Primary_Button') + expect(continueBtn).toBeDisabled() + expect(vi.mocked(InputField)).toHaveBeenCalledWith( + { + title: 'Aspirate volume per well (µL)', + error: 'Value must be between 5-50', + readOnly: true, + type: 'text', + value: '90', + }, + {} + ) + }) +}) diff --git a/app/src/organisms/QuickTransferFlow/__tests__/utils.test.ts b/app/src/organisms/QuickTransferFlow/__tests__/utils.test.ts new file mode 100644 index 00000000000..7cb4c7e1495 --- /dev/null +++ b/app/src/organisms/QuickTransferFlow/__tests__/utils.test.ts @@ -0,0 +1,108 @@ +import { describe, it, expect } from 'vitest' +import { getVolumeLimits, generateCompatibleLabwareForPipette } from '../utils' +import { + SINGLE_CHANNEL_COMPATIBLE_LABWARE, + EIGHT_CHANNEL_COMPATIBLE_LABWARE, + NINETY_SIX_CHANNEL_COMPATIBLE_LABWARE, +} from '../constants' + +import type { QuickTransferSetupState } from '../types' + +describe('getVolumeLimits', () => { + const state: QuickTransferSetupState = { + pipette: { + liquids: [ + { + maxVolume: 1000, + minVolume: 5, + }, + ] as any, + } as any, + tipRack: { + wells: { + A1: { + totalLiquidVolume: 200, + }, + } as any, + } as any, + source: { + wells: { + A1: { + totalLiquidVolume: 200, + }, + A2: { + totalLiquidVolume: 75, + }, + A3: { + totalLiquidVolume: 100, + }, + } as any, + } as any, + sourceWells: ['A1'], + destination: { + wells: { + A1: { + totalLiquidVolume: 1000, + }, + A2: { + totalLiquidVolume: 1000, + }, + } as any, + } as any, + destinationWells: ['A1'], + } + it('calculates the range for a 1 to 1 transfer', () => { + const result = getVolumeLimits(state) + expect(result.min).toEqual(5) + // should equal lesser of pipette max, tip capacity, volume of all selected wells + expect(result.max).toEqual(200) + }) + it('calculates the range for an n to 1 transfer', () => { + const result = getVolumeLimits({ ...state, sourceWells: ['A1', 'A2'] }) + expect(result.min).toEqual(5) + // should equal lesser of pipette max, tip capacity, volume of all + // selected source wells and 1 / 2 volume of destination well + expect(result.max).toEqual(75) + }) + it('calculates the range for an 1 to n transfer', () => { + const result = getVolumeLimits({ ...state, destinationWells: ['A1', 'A2'] }) + expect(result.min).toEqual(5) + // should equal lesser of pipette max, tip capacity, volume of all + // selected destination wells and 1 / 2 volume of source well + expect(result.max).toEqual(100) + }) + it('calculates the range for 1 to n transfer with same labware', () => { + const result = getVolumeLimits({ + ...state, + destination: 'source', + destinationWells: ['A2', 'A3'], + }) + expect(result.min).toEqual(5) + // should equal lesser of pipette max, tip capacity, volume of all + // selected destination wells and 1 / 2 volume of source well + expect(result.max).toEqual(75) + }) +}) + +// if one of these fails, it is likely that a new definition has been added +// and you need to regenerate the lists stored at ../constants +describe('generateCompatibleLabwareForPipette', () => { + it('generates the list for single channel pipettes', () => { + const compatibleLabwareUris = generateCompatibleLabwareForPipette({ + channels: 1, + } as any) + expect(compatibleLabwareUris).toEqual(SINGLE_CHANNEL_COMPATIBLE_LABWARE) + }) + it('generates the list for eight channel pipettes', () => { + const compatibleLabwareUris = generateCompatibleLabwareForPipette({ + channels: 8, + } as any) + expect(compatibleLabwareUris).toEqual(EIGHT_CHANNEL_COMPATIBLE_LABWARE) + }) + it('generates the list for 96 channel pipettes', () => { + const compatibleLabwareUris = generateCompatibleLabwareForPipette({ + channels: 96, + } as any) + expect(compatibleLabwareUris).toEqual(NINETY_SIX_CHANNEL_COMPATIBLE_LABWARE) + }) +}) diff --git a/app/src/organisms/QuickTransferFlow/constants.ts b/app/src/organisms/QuickTransferFlow/constants.ts new file mode 100644 index 00000000000..9fa3a8fc28b --- /dev/null +++ b/app/src/organisms/QuickTransferFlow/constants.ts @@ -0,0 +1,177 @@ +export const ACTIONS = { + SELECT_PIPETTE: 'SELECT_PIPETTE', + SELECT_TIP_RACK: 'SELECT_TIP_RACK', + SET_SOURCE_LABWARE: 'SET_SOURCE_LABWARE', + SET_SOURCE_WELLS: 'SET_SOURCE_WELLS', + SET_DEST_LABWARE: 'SET_DEST_LABWARE', + SET_DEST_WELLS: 'SET_DEST_WELLS', + SET_VOLUME: 'SET_VOLUME', +} as const + +// these lists are generated by the util generateCompatibleLabwareForPipette in ./utils +export const SINGLE_CHANNEL_COMPATIBLE_LABWARE = [ + 'opentrons/agilent_1_reservoir_290ml/1', + 'opentrons/appliedbiosystemsmicroamp_384_wellplate_40ul/1', + 'opentrons/axygen_1_reservoir_90ml/1', + 'opentrons/biorad_384_wellplate_50ul/2', + 'opentrons/biorad_96_wellplate_200ul_pcr/2', + 'opentrons/corning_12_wellplate_6.9ml_flat/2', + 'opentrons/corning_24_wellplate_3.4ml_flat/2', + 'opentrons/corning_384_wellplate_112ul_flat/2', + 'opentrons/corning_48_wellplate_1.6ml_flat/2', + 'opentrons/corning_6_wellplate_16.8ml_flat/2', + 'opentrons/corning_96_wellplate_360ul_flat/2', + 'opentrons/geb_96_tiprack_1000ul/1', + 'opentrons/geb_96_tiprack_10ul/1', + 'opentrons/nest_12_reservoir_15ml/1', + 'opentrons/nest_1_reservoir_195ml/2', + 'opentrons/nest_1_reservoir_290ml/1', + 'opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2', + 'opentrons/nest_96_wellplate_200ul_flat/2', + 'opentrons/nest_96_wellplate_2ml_deep/2', + 'opentrons/opentrons_10_tuberack_falcon_4x50ml_6x15ml_conical/1', + 'opentrons/opentrons_10_tuberack_nest_4x50ml_6x15ml_conical/1', + 'opentrons/opentrons_15_tuberack_falcon_15ml_conical/1', + 'opentrons/opentrons_15_tuberack_nest_15ml_conical/1', + 'opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/2', + 'opentrons/opentrons_24_aluminumblock_nest_0.5ml_screwcap/1', + 'opentrons/opentrons_24_aluminumblock_nest_1.5ml_screwcap/1', + 'opentrons/opentrons_24_aluminumblock_nest_1.5ml_snapcap/1', + 'opentrons/opentrons_24_aluminumblock_nest_2ml_screwcap/1', + 'opentrons/opentrons_24_aluminumblock_nest_2ml_snapcap/1', + 'opentrons/opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap/1', + 'opentrons/opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap/1', + 'opentrons/opentrons_24_tuberack_generic_2ml_screwcap/1', + 'opentrons/opentrons_24_tuberack_nest_0.5ml_screwcap/1', + 'opentrons/opentrons_24_tuberack_nest_1.5ml_screwcap/1', + 'opentrons/opentrons_24_tuberack_nest_1.5ml_snapcap/1', + 'opentrons/opentrons_24_tuberack_nest_2ml_screwcap/1', + 'opentrons/opentrons_24_tuberack_nest_2ml_snapcap/1', + 'opentrons/opentrons_6_tuberack_falcon_50ml_conical/1', + 'opentrons/opentrons_6_tuberack_nest_50ml_conical/1', + 'opentrons/opentrons_96_aluminumblock_biorad_wellplate_200ul/1', + 'opentrons/opentrons_96_aluminumblock_generic_pcr_strip_200ul/2', + 'opentrons/opentrons_96_aluminumblock_nest_wellplate_100ul/1', + 'opentrons/opentrons_96_deep_well_adapter/1', + 'opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1', + 'opentrons/opentrons_96_filtertiprack_1000ul/1', + 'opentrons/opentrons_96_filtertiprack_10ul/1', + 'opentrons/opentrons_96_filtertiprack_200ul/1', + 'opentrons/opentrons_96_filtertiprack_20ul/1', + 'opentrons/opentrons_96_flat_bottom_adapter/1', + 'opentrons/opentrons_96_flat_bottom_adapter_nest_wellplate_200ul_flat/1', + 'opentrons/opentrons_96_pcr_adapter/1', + 'opentrons/opentrons_96_pcr_adapter_nest_wellplate_100ul_pcr_full_skirt/1', + 'opentrons/opentrons_96_tiprack_1000ul/1', + 'opentrons/opentrons_96_tiprack_10ul/1', + 'opentrons/opentrons_96_tiprack_20ul/1', + 'opentrons/opentrons_96_tiprack_300ul/1', + 'opentrons/opentrons_96_well_aluminum_block/1', + 'opentrons/opentrons_96_wellplate_200ul_pcr_full_skirt/2', + 'opentrons/opentrons_aluminum_flat_bottom_plate/1', + 'opentrons/opentrons_flex_96_filtertiprack_1000ul/1', + 'opentrons/opentrons_flex_96_filtertiprack_200ul/1', + 'opentrons/opentrons_flex_96_filtertiprack_50ul/1', + 'opentrons/opentrons_flex_96_tiprack_1000ul/1', + 'opentrons/opentrons_flex_96_tiprack_200ul/1', + 'opentrons/opentrons_flex_96_tiprack_50ul/1', + 'opentrons/opentrons_flex_96_tiprack_adapter/1', + 'opentrons/opentrons_universal_flat_adapter/1', + 'opentrons/opentrons_universal_flat_adapter_corning_384_wellplate_112ul_flat/1', + 'opentrons/thermoscientificnunc_96_wellplate_1300ul/1', + 'opentrons/thermoscientificnunc_96_wellplate_2000ul/1', + 'opentrons/usascientific_12_reservoir_22ml/1', + 'opentrons/usascientific_96_wellplate_2.4ml_deep/1', +] + +export const EIGHT_CHANNEL_COMPATIBLE_LABWARE = [ + 'opentrons/agilent_1_reservoir_290ml/1', + 'opentrons/appliedbiosystemsmicroamp_384_wellplate_40ul/1', + 'opentrons/axygen_1_reservoir_90ml/1', + 'opentrons/biorad_384_wellplate_50ul/2', + 'opentrons/biorad_96_wellplate_200ul_pcr/2', + 'opentrons/corning_384_wellplate_112ul_flat/2', + 'opentrons/corning_96_wellplate_360ul_flat/2', + 'opentrons/geb_96_tiprack_1000ul/1', + 'opentrons/geb_96_tiprack_10ul/1', + 'opentrons/nest_12_reservoir_15ml/1', + 'opentrons/nest_1_reservoir_195ml/2', + 'opentrons/nest_1_reservoir_290ml/1', + 'opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2', + 'opentrons/nest_96_wellplate_200ul_flat/2', + 'opentrons/nest_96_wellplate_2ml_deep/2', + 'opentrons/opentrons_96_aluminumblock_biorad_wellplate_200ul/1', + 'opentrons/opentrons_96_aluminumblock_generic_pcr_strip_200ul/2', + 'opentrons/opentrons_96_aluminumblock_nest_wellplate_100ul/1', + 'opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1', + 'opentrons/opentrons_96_filtertiprack_1000ul/1', + 'opentrons/opentrons_96_filtertiprack_10ul/1', + 'opentrons/opentrons_96_filtertiprack_200ul/1', + 'opentrons/opentrons_96_filtertiprack_20ul/1', + 'opentrons/opentrons_96_flat_bottom_adapter_nest_wellplate_200ul_flat/1', + 'opentrons/opentrons_96_pcr_adapter/1', + 'opentrons/opentrons_96_pcr_adapter_nest_wellplate_100ul_pcr_full_skirt/1', + 'opentrons/opentrons_96_tiprack_1000ul/1', + 'opentrons/opentrons_96_tiprack_10ul/1', + 'opentrons/opentrons_96_tiprack_20ul/1', + 'opentrons/opentrons_96_tiprack_300ul/1', + 'opentrons/opentrons_96_well_aluminum_block/1', + 'opentrons/opentrons_96_wellplate_200ul_pcr_full_skirt/2', + 'opentrons/opentrons_flex_96_filtertiprack_1000ul/1', + 'opentrons/opentrons_flex_96_filtertiprack_200ul/1', + 'opentrons/opentrons_flex_96_filtertiprack_50ul/1', + 'opentrons/opentrons_flex_96_tiprack_1000ul/1', + 'opentrons/opentrons_flex_96_tiprack_200ul/1', + 'opentrons/opentrons_flex_96_tiprack_50ul/1', + 'opentrons/opentrons_universal_flat_adapter_corning_384_wellplate_112ul_flat/1', + 'opentrons/thermoscientificnunc_96_wellplate_1300ul/1', + 'opentrons/thermoscientificnunc_96_wellplate_2000ul/1', + 'opentrons/usascientific_12_reservoir_22ml/1', + 'opentrons/usascientific_96_wellplate_2.4ml_deep/1', +] + +export const NINETY_SIX_CHANNEL_COMPATIBLE_LABWARE = [ + 'opentrons/agilent_1_reservoir_290ml/1', + 'opentrons/appliedbiosystemsmicroamp_384_wellplate_40ul/1', + 'opentrons/axygen_1_reservoir_90ml/1', + 'opentrons/biorad_384_wellplate_50ul/2', + 'opentrons/biorad_96_wellplate_200ul_pcr/2', + 'opentrons/corning_384_wellplate_112ul_flat/2', + 'opentrons/corning_96_wellplate_360ul_flat/2', + 'opentrons/geb_96_tiprack_1000ul/1', + 'opentrons/geb_96_tiprack_10ul/1', + 'opentrons/nest_12_reservoir_15ml/1', + 'opentrons/nest_1_reservoir_195ml/2', + 'opentrons/nest_1_reservoir_290ml/1', + 'opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2', + 'opentrons/nest_96_wellplate_200ul_flat/2', + 'opentrons/nest_96_wellplate_2ml_deep/2', + 'opentrons/opentrons_96_aluminumblock_biorad_wellplate_200ul/1', + 'opentrons/opentrons_96_aluminumblock_generic_pcr_strip_200ul/2', + 'opentrons/opentrons_96_aluminumblock_nest_wellplate_100ul/1', + 'opentrons/opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep/1', + 'opentrons/opentrons_96_filtertiprack_1000ul/1', + 'opentrons/opentrons_96_filtertiprack_10ul/1', + 'opentrons/opentrons_96_filtertiprack_200ul/1', + 'opentrons/opentrons_96_filtertiprack_20ul/1', + 'opentrons/opentrons_96_flat_bottom_adapter_nest_wellplate_200ul_flat/1', + 'opentrons/opentrons_96_pcr_adapter/1', + 'opentrons/opentrons_96_pcr_adapter_nest_wellplate_100ul_pcr_full_skirt/1', + 'opentrons/opentrons_96_tiprack_1000ul/1', + 'opentrons/opentrons_96_tiprack_10ul/1', + 'opentrons/opentrons_96_tiprack_20ul/1', + 'opentrons/opentrons_96_tiprack_300ul/1', + 'opentrons/opentrons_96_well_aluminum_block/1', + 'opentrons/opentrons_96_wellplate_200ul_pcr_full_skirt/2', + 'opentrons/opentrons_flex_96_filtertiprack_1000ul/1', + 'opentrons/opentrons_flex_96_filtertiprack_200ul/1', + 'opentrons/opentrons_flex_96_filtertiprack_50ul/1', + 'opentrons/opentrons_flex_96_tiprack_1000ul/1', + 'opentrons/opentrons_flex_96_tiprack_200ul/1', + 'opentrons/opentrons_flex_96_tiprack_50ul/1', + 'opentrons/opentrons_universal_flat_adapter_corning_384_wellplate_112ul_flat/1', + 'opentrons/thermoscientificnunc_96_wellplate_1300ul/1', + 'opentrons/thermoscientificnunc_96_wellplate_2000ul/1', + 'opentrons/usascientific_12_reservoir_22ml/1', + 'opentrons/usascientific_96_wellplate_2.4ml_deep/1', +] diff --git a/app/src/organisms/QuickTransferFlow/index.tsx b/app/src/organisms/QuickTransferFlow/index.tsx new file mode 100644 index 00000000000..fe70233bdde --- /dev/null +++ b/app/src/organisms/QuickTransferFlow/index.tsx @@ -0,0 +1,95 @@ +import * as React from 'react' +import { useHistory } from 'react-router-dom' +import { useTranslation } from 'react-i18next' +import { + useConditionalConfirm, + StepMeter, + POSITION_STICKY, +} from '@opentrons/components' +import { SmallButton } from '../../atoms/buttons' +import { ConfirmExitModal } from './ConfirmExitModal' +import { CreateNewTransfer } from './CreateNewTransfer' +import { SelectPipette } from './SelectPipette' +import { SelectTipRack } from './SelectTipRack' +import { SelectSourceLabware } from './SelectSourceLabware' +import { SelectSourceWells } from './SelectSourceWells' +import { SelectDestLabware } from './SelectDestLabware' +import { SelectDestWells } from './SelectDestWells' +import { VolumeEntry } from './VolumeEntry' +import { quickTransferReducer } from './utils' + +import type { QuickTransferSetupState } from './types' + +const QUICK_TRANSFER_WIZARD_STEPS = 8 +const initialQuickTransferState: QuickTransferSetupState = {} + +export const QuickTransferFlow = (): JSX.Element => { + const history = useHistory() + const { i18n, t } = useTranslation(['quick_transfer', 'shared']) + const [state, dispatch] = React.useReducer( + quickTransferReducer, + initialQuickTransferState + ) + const [currentStep, setCurrentStep] = React.useState(1) + + const { + confirm: confirmExit, + showConfirmation: showConfirmExit, + cancel: cancelExit, + } = useConditionalConfirm(() => history.push('protocols'), true) + + React.useEffect(() => { + if (state.volume != null) { + // until summary screen is implemented, log the final state and close flow + // once volume is set + console.log('final quick transfer flow state:', state) + history.push('protocols') + } + }, [state.volume]) + + const exitButtonProps: React.ComponentProps = { + buttonType: 'tertiaryLowLight', + buttonText: i18n.format(t('shared:exit'), 'capitalize'), + onClick: confirmExit, + } + const sharedMiddleStepProps = { + state, + dispatch, + onBack: () => setCurrentStep(prevStep => prevStep - 1), + onNext: () => setCurrentStep(prevStep => prevStep + 1), + exitButtonProps, + } + + const modalContentInOrder: JSX.Element[] = [ + setCurrentStep(prevStep => prevStep + 1)} + exitButtonProps={exitButtonProps} + />, + , + , + , + , + , + , + {}} />, + ] + + return ( + <> + {showConfirmExit ? ( + + ) : ( + <> + + {modalContentInOrder[currentStep]} + + )} + + ) +} diff --git a/app/src/organisms/QuickTransferFlow/types.ts b/app/src/organisms/QuickTransferFlow/types.ts new file mode 100644 index 00000000000..b9c2d788ca8 --- /dev/null +++ b/app/src/organisms/QuickTransferFlow/types.ts @@ -0,0 +1,53 @@ +import { ACTIONS } from './constants' +import type { Mount } from '@opentrons/api-client' +import type { LabwareDefinition2, PipetteV2Specs } from '@opentrons/shared-data' + +export interface QuickTransferSetupState { + pipette?: PipetteV2Specs + mount?: Mount + tipRack?: LabwareDefinition2 + source?: LabwareDefinition2 + sourceWells?: string[] + destination?: LabwareDefinition2 | 'source' + destinationWells?: string[] + volume?: number +} + +export type QuickTransferWizardAction = + | SelectPipetteAction + | SelectTipRackAction + | SetSourceLabwareAction + | SetSourceWellsAction + | SetDestLabwareAction + | SetDestWellsAction + | SetVolumeAction + +interface SelectPipetteAction { + type: typeof ACTIONS.SELECT_PIPETTE + mount: Mount + pipette: PipetteV2Specs +} +interface SelectTipRackAction { + type: typeof ACTIONS.SELECT_TIP_RACK + tipRack: LabwareDefinition2 +} +interface SetSourceLabwareAction { + type: typeof ACTIONS.SET_SOURCE_LABWARE + labware: LabwareDefinition2 +} +interface SetSourceWellsAction { + type: typeof ACTIONS.SET_SOURCE_WELLS + wells: string[] +} +interface SetDestLabwareAction { + type: typeof ACTIONS.SET_DEST_LABWARE + labware: LabwareDefinition2 | 'source' +} +interface SetDestWellsAction { + type: typeof ACTIONS.SET_DEST_WELLS + wells: string[] +} +interface SetVolumeAction { + type: typeof ACTIONS.SET_VOLUME + volume: number +} diff --git a/app/src/organisms/QuickTransferFlow/utils.ts b/app/src/organisms/QuickTransferFlow/utils.ts new file mode 100644 index 00000000000..41de2d86269 --- /dev/null +++ b/app/src/organisms/QuickTransferFlow/utils.ts @@ -0,0 +1,230 @@ +import { + makeWellSetHelpers, + getLabwareDefURI, + getAllDefinitions, +} from '@opentrons/shared-data' +import { getAllDefinitions as getAllLatestDefValues } from '../../pages/Labware/helpers/definitions' +import { + SINGLE_CHANNEL_COMPATIBLE_LABWARE, + EIGHT_CHANNEL_COMPATIBLE_LABWARE, + NINETY_SIX_CHANNEL_COMPATIBLE_LABWARE, +} from './constants' + +import type { + LabwareDefinition2, + PipetteV2Specs, + WellSetHelpers, +} from '@opentrons/shared-data' +import type { + QuickTransferSetupState, + QuickTransferWizardAction, +} from './types' +import type { LabwareFilter } from '../../pages/Labware/types' + +export function quickTransferReducer( + state: QuickTransferSetupState, + action: QuickTransferWizardAction +): QuickTransferSetupState { + switch (action.type) { + case 'SELECT_PIPETTE': { + return { + pipette: action.pipette, + mount: action.mount, + } + } + case 'SELECT_TIP_RACK': { + return { + pipette: state.pipette, + mount: state.mount, + tipRack: action.tipRack, + } + } + case 'SET_SOURCE_LABWARE': { + return { + pipette: state.pipette, + mount: state.mount, + tipRack: state.tipRack, + source: action.labware, + } + } + case 'SET_SOURCE_WELLS': { + return { + pipette: state.pipette, + mount: state.mount, + tipRack: state.tipRack, + source: state.source, + sourceWells: action.wells, + } + } + case 'SET_DEST_LABWARE': { + return { + pipette: state.pipette, + mount: state.mount, + tipRack: state.tipRack, + source: state.source, + sourceWells: state.sourceWells, + destination: action.labware, + } + } + case 'SET_DEST_WELLS': { + return { + pipette: state.pipette, + mount: state.mount, + tipRack: state.tipRack, + source: state.source, + sourceWells: state.sourceWells, + destination: state.destination, + destinationWells: action.wells, + } + } + case 'SET_VOLUME': { + return { + pipette: state.pipette, + mount: state.mount, + tipRack: state.tipRack, + source: state.source, + sourceWells: state.sourceWells, + destination: state.destination, + destinationWells: state.destinationWells, + volume: action.volume, + } + } + } +} + +export function getCompatibleLabwareByCategory( + pipetteChannels: 1 | 8 | 96, + category: LabwareFilter +): LabwareDefinition2[] | undefined { + const allLabwareDefinitions = getAllDefinitions() + let compatibleLabwareUris: string[] = SINGLE_CHANNEL_COMPATIBLE_LABWARE + if (pipetteChannels === 8) { + compatibleLabwareUris = EIGHT_CHANNEL_COMPATIBLE_LABWARE + } else if (pipetteChannels === 96) { + compatibleLabwareUris = NINETY_SIX_CHANNEL_COMPATIBLE_LABWARE + } + + const compatibleLabwareDefinitions = compatibleLabwareUris.reduce< + LabwareDefinition2[] + >((acc, defUri) => { + return [...acc, allLabwareDefinitions[defUri]] + }, []) + + if (category === 'all') { + return compatibleLabwareDefinitions.filter( + def => + def.metadata.displayCategory === 'reservoir' || + def.metadata.displayCategory === 'tubeRack' || + def.metadata.displayCategory === 'wellPlate' + ) + } else if (category === 'reservoir') { + return compatibleLabwareDefinitions.filter( + def => def.metadata.displayCategory === 'reservoir' + ) + } else if (category === 'tubeRack') { + return compatibleLabwareDefinitions.filter( + def => def.metadata.displayCategory === 'tubeRack' + ) + } else if (category === 'wellPlate') { + return compatibleLabwareDefinitions.filter( + def => def.metadata.displayCategory === 'wellPlate' + ) + } +} + +export function getVolumeLimits( + state: QuickTransferSetupState +): { min: number; max: number } { + if ( + state.pipette == null || + state.tipRack == null || + state.source == null || + state.sourceWells == null || + state.destination == null || + state.destinationWells == null + ) { + // this should only be called once all state values are set + return { min: 0, max: 0 } + } + + const minPipetteVolume = Object.values(state.pipette.liquids)[0].minVolume + const maxPipetteVolume = Object.values(state.pipette.liquids)[0].maxVolume + const tipRackVolume = Object.values(state.tipRack.wells)[0].totalLiquidVolume + const sourceLabwareVolume = Math.min( + ...state.sourceWells.map(well => + state.source ? state.source.wells[well].totalLiquidVolume : 0 + ) + ) + + const destLabwareVolume = Math.min( + ...state.destinationWells.map(well => { + if (state.source == null || state.destination == null) return 0 + return state.destination === 'source' + ? state.source.wells[well].totalLiquidVolume + : state.destination.wells[well].totalLiquidVolume + }) + ) + let maxVolume = maxPipetteVolume + if (state.sourceWells.length === state.destinationWells.length) { + // 1 to 1 transfer + maxVolume = Math.min( + ...[ + maxPipetteVolume, + tipRackVolume, + sourceLabwareVolume, + destLabwareVolume, + ] + ) + } else if (state.sourceWells.length < state.destinationWells.length) { + // 1 to n transfer + const ratio = state.sourceWells.length / state.destinationWells.length + + maxVolume = Math.min( + ...[ + maxPipetteVolume, + tipRackVolume, + sourceLabwareVolume * ratio, + destLabwareVolume, + ] + ) + } else if (state.sourceWells.length > state.destinationWells.length) { + // n to 1 transfer + const ratio = state.destinationWells.length / state.sourceWells.length + + maxVolume = Math.min( + ...[ + maxPipetteVolume, + tipRackVolume, + sourceLabwareVolume, + destLabwareVolume * ratio, + ] + ) + } + + return { min: minPipetteVolume, max: maxVolume } +} + +export function generateCompatibleLabwareForPipette( + pipetteSpecs: PipetteV2Specs +): string[] { + const allLabwareDefinitions = getAllLatestDefValues() + const wellSetHelpers: WellSetHelpers = makeWellSetHelpers() + const { canPipetteUseLabware } = wellSetHelpers + + const compatibleDefUriList = allLabwareDefinitions.reduce( + (acc, definition) => { + if (pipetteSpecs.channels === 1) { + return [...acc, getLabwareDefURI(definition)] + } else { + const isCompatible = canPipetteUseLabware(pipetteSpecs, definition) + return isCompatible ? [...acc, getLabwareDefURI(definition)] : acc + } + }, + [] + ) + + // console.log(JSON.stringify(compatibleDefUriList)) + // to update this list, uncomment the above log statement and + // paste the result into the const in ./constants.ts + return compatibleDefUriList +} diff --git a/app/src/organisms/RobotSettingsDashboard/Privacy.tsx b/app/src/organisms/RobotSettingsDashboard/Privacy.tsx index ceca1dea718..7f8963b15e8 100644 --- a/app/src/organisms/RobotSettingsDashboard/Privacy.tsx +++ b/app/src/organisms/RobotSettingsDashboard/Privacy.tsx @@ -32,7 +32,7 @@ export function Privacy({ robotName, setCurrentOption, }: PrivacyProps): JSX.Element { - const { t } = useTranslation('app_settings') + const { t } = useTranslation(['app_settings', 'branded']) const dispatch = useDispatch() const allRobotSettings = useSelector((state: State) => @@ -62,7 +62,7 @@ export function Privacy({ lineHeight={TYPOGRAPHY.lineHeight36} fontWeight={TYPOGRAPHY.fontWeightRegular} > - {t('opentrons_cares_about_privacy')} + {t('branded:opentrons_cares_about_privacy')}
} onClick={() => dispatch(toggleAnalyticsOptedIn())} diff --git a/app/src/organisms/RobotSettingsDashboard/RobotSystemVersion.tsx b/app/src/organisms/RobotSettingsDashboard/RobotSystemVersion.tsx index f5f6aeb7391..40b04d34fd9 100644 --- a/app/src/organisms/RobotSettingsDashboard/RobotSystemVersion.tsx +++ b/app/src/organisms/RobotSettingsDashboard/RobotSystemVersion.tsx @@ -40,6 +40,7 @@ export function RobotSystemVersion({ 'shared', 'device_details', 'app_settings', + 'branded', ]) const [showModal, setShowModal] = React.useState(isUpdateAvailable) @@ -76,7 +77,7 @@ export function RobotSystemVersion({ > - {t('view_latest_release_notes_at', { url: GITHUB_URL })} + {t('branded:view_latest_release_notes_at', { url: GITHUB_URL })} diff --git a/app/src/organisms/RunDetails/ConfirmCancelModal.tsx b/app/src/organisms/RunDetails/ConfirmCancelModal.tsx index 172d8b15394..2e1b6b5238f 100644 --- a/app/src/organisms/RunDetails/ConfirmCancelModal.tsx +++ b/app/src/organisms/RunDetails/ConfirmCancelModal.tsx @@ -22,9 +22,9 @@ import { useStopRunMutation } from '@opentrons/react-api-client' import { getModalPortalEl } from '../../App/portal' import { LegacyModal } from '../../molecules/LegacyModal' -import { useTrackProtocolRunEvent } from '../Devices/hooks' +import { useTrackProtocolRunEvent, useIsFlex } from '../Devices/hooks' import { useRunStatus } from '../RunTimeControl/hooks' -import { ANALYTICS_PROTOCOL_RUN_CANCEL } from '../../redux/analytics' +import { ANALYTICS_PROTOCOL_RUN_ACTION } from '../../redux/analytics' export interface ConfirmCancelModalProps { onClose: () => unknown @@ -39,16 +39,21 @@ export function ConfirmCancelModal( const { stopRun } = useStopRunMutation() const [isCanceling, setIsCanceling] = React.useState(false) const runStatus = useRunStatus(runId) + const isFlex = useIsFlex(robotName) const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId, robotName) const { t } = useTranslation('run_details') + const cancelRunAlertInfo = isFlex + ? t('cancel_run_alert_info_flex') + : t('cancel_run_alert_info_ot2') + const cancelRun: React.MouseEventHandler = (e): void => { e.preventDefault() e.stopPropagation() setIsCanceling(true) stopRun(runId, { onSuccess: () => { - trackProtocolRunEvent({ name: ANALYTICS_PROTOCOL_RUN_CANCEL }) + trackProtocolRunEvent({ name: ANALYTICS_PROTOCOL_RUN_ACTION.CANCEL }) }, onError: () => { setIsCanceling(false) @@ -72,7 +77,7 @@ export function ConfirmCancelModal( > - {t('cancel_run_alert_info')} + {cancelRunAlertInfo} {t('cancel_run_module_info')} diff --git a/app/src/organisms/RunDetails/__tests__/ConfirmCancelModal.test.tsx b/app/src/organisms/RunDetails/__tests__/ConfirmCancelModal.test.tsx index 872a23b8daa..92fed1f5e4f 100644 --- a/app/src/organisms/RunDetails/__tests__/ConfirmCancelModal.test.tsx +++ b/app/src/organisms/RunDetails/__tests__/ConfirmCancelModal.test.tsx @@ -11,7 +11,10 @@ import { import { useStopRunMutation } from '@opentrons/react-api-client' import { i18n } from '../../../i18n' -import { useTrackProtocolRunEvent } from '../../../organisms/Devices/hooks' +import { + useIsFlex, + useTrackProtocolRunEvent, +} from '../../../organisms/Devices/hooks' import { useTrackEvent } from '../../../redux/analytics' import { renderWithProviders } from '../../../__testing-utils__' import { ConfirmCancelModal } from '../../../organisms/RunDetails/ConfirmCancelModal' @@ -56,6 +59,7 @@ describe('ConfirmCancelModal', () => { when(useTrackProtocolRunEvent).calledWith(RUN_ID, ROBOT_NAME).thenReturn({ trackProtocolRunEvent: mockTrackProtocolRunEvent, }) + vi.mocked(useIsFlex).mockReturnValue(true) props = { onClose: vi.fn(), runId: RUN_ID, robotName: ROBOT_NAME } }) @@ -66,15 +70,20 @@ describe('ConfirmCancelModal', () => { it('should render the correct title', () => { render(props) - screen.getByText('Are you sure you want to cancel this run?') + screen.getByText('Are you sure you want to cancel?') }) - it('should render the correct body', () => { + it('should render the correct body text for a Flex', () => { render(props) + screen.getByText('Doing so will terminate this run and home your robot.') screen.getByText( - 'Doing so will terminate this run, drop any attached tips in the trash container and home your robot.' + 'Additionally, any hardware modules used within the protocol will remain active and maintain their current states until deactivated.' ) + }) + it('should render correct alternative body text for an OT-2', () => { + vi.mocked(useIsFlex).mockReturnValue(false) + render(props) screen.getByText( - 'Additionally, any hardware modules used within the protocol will remain active and maintain their current states until deactivated.' + 'Doing so will terminate this run, drop any attached tips in the trash container, and home your robot.' ) }) it('should render both buttons', () => { diff --git a/app/src/organisms/RunPreview/index.tsx b/app/src/organisms/RunPreview/index.tsx index a75257c1952..7e2f74238bd 100644 --- a/app/src/organisms/RunPreview/index.tsx +++ b/app/src/organisms/RunPreview/index.tsx @@ -3,6 +3,7 @@ import { css } from 'styled-components' import { useTranslation } from 'react-i18next' import { ViewportList, ViewportListRef } from 'react-viewport-list' +import { RUN_STATUSES_TERMINAL } from '@opentrons/api-client' import { ALIGN_CENTER, BORDERS, @@ -19,15 +20,23 @@ import { } from '@opentrons/components' import { useMostRecentCompletedAnalysis } from '../LabwarePositionCheck/useMostRecentCompletedAnalysis' -import { useNotifyLastRunCommandKey } from '../../resources/runs' +import { + useNotifyLastRunCommand, + useNotifyAllCommandsAsPreSerializedList, +} from '../../resources/runs' import { CommandText } from '../CommandText' import { Divider } from '../../atoms/structure' import { NAV_BAR_WIDTH } from '../../App/constants' import { CommandIcon } from './CommandIcon' +import { useRunStatus } from '../RunTimeControl/hooks' + +import type { RunStatus } from '@opentrons/api-client' import type { RobotType } from '@opentrons/shared-data' const COLOR_FADE_MS = 500 const LIVE_RUN_COMMANDS_POLL_MS = 3000 +// arbitrary large number of commands +const MAX_COMMANDS = 100000 interface RunPreviewProps { runId: string @@ -41,16 +50,37 @@ export const RunPreviewComponent = ( ): JSX.Element | null => { const { t } = useTranslation('run_details') const robotSideAnalysis = useMostRecentCompletedAnalysis(runId) + const runStatus = useRunStatus(runId) + const isRunTerminal = + runStatus != null + ? (RUN_STATUSES_TERMINAL as RunStatus[]).includes(runStatus) + : false + // we only ever want one request done for terminal runs because this is a heavy request + const commandsFromQuery = useNotifyAllCommandsAsPreSerializedList( + runId, + { cursor: 0, pageLength: MAX_COMMANDS }, + { + staleTime: Infinity, + cacheTime: Infinity, + enabled: isRunTerminal, + } + ).data?.data + const nullCheckedCommandsFromQuery = + commandsFromQuery == null ? robotSideAnalysis?.commands : commandsFromQuery const viewPortRef = React.useRef(null) - const currentRunCommandKey = useNotifyLastRunCommandKey(runId, { + const currentRunCommandKey = useNotifyLastRunCommand(runId, { refetchInterval: LIVE_RUN_COMMANDS_POLL_MS, - }) + })?.key const [ isCurrentCommandVisible, setIsCurrentCommandVisible, ] = React.useState(true) if (robotSideAnalysis == null) return null - const currentRunCommandIndex = robotSideAnalysis.commands.findIndex( + const commands = + (isRunTerminal + ? nullCheckedCommandsFromQuery + : robotSideAnalysis.commands) ?? [] + const currentRunCommandIndex = commands.findIndex( c => c.key === currentRunCommandKey ) @@ -69,7 +99,7 @@ export const RunPreviewComponent = ( {t('run_preview')} - {t('steps_total', { count: robotSideAnalysis.commands.length })} + {t('steps_total', { count: commands.length })} @@ -79,7 +109,7 @@ export const RunPreviewComponent = ( ) : null} - {currentRunCommandIndex === robotSideAnalysis.commands.length - 1 ? ( + {currentRunCommandIndex === commands.length - 1 ? ( {t('end_of_protocol')} diff --git a/app/src/organisms/RunProgressMeter/__tests__/RunProgressMeter.test.tsx b/app/src/organisms/RunProgressMeter/__tests__/RunProgressMeter.test.tsx index aba56366b27..7a40319e050 100644 --- a/app/src/organisms/RunProgressMeter/__tests__/RunProgressMeter.test.tsx +++ b/app/src/organisms/RunProgressMeter/__tests__/RunProgressMeter.test.tsx @@ -11,6 +11,7 @@ import { RUN_STATUS_IDLE, RUN_STATUS_RUNNING, RUN_STATUS_SUCCEEDED, + RunCommandSummary, } from '@opentrons/api-client' import { i18n } from '../../../i18n' @@ -19,7 +20,7 @@ import { ProgressBar } from '../../../atoms/ProgressBar' import { useRunStatus } from '../../RunTimeControl/hooks' import { useMostRecentCompletedAnalysis } from '../../LabwarePositionCheck/useMostRecentCompletedAnalysis' import { - useNotifyLastRunCommandKey, + useNotifyLastRunCommand, useNotifyRunQuery, } from '../../../resources/runs' import { useDownloadRunLog } from '../../Devices/hooks' @@ -82,9 +83,9 @@ describe('RunProgressMeter', () => { downloadRunLog: vi.fn(), isRunLogLoading: false, }) - when(useNotifyLastRunCommandKey) + when(useNotifyLastRunCommand) .calledWith(NON_DETERMINISTIC_RUN_ID, { refetchInterval: 1000 }) - .thenReturn(NON_DETERMINISTIC_COMMAND_KEY) + .thenReturn({ key: NON_DETERMINISTIC_COMMAND_KEY } as RunCommandSummary) vi.mocked(useNotifyRunQuery).mockReturnValue({ data: null } as any) diff --git a/app/src/organisms/RunTimeControl/__fixtures__/index.ts b/app/src/organisms/RunTimeControl/__fixtures__/index.ts index 1a18a9a6bcf..33f2e0c4393 100644 --- a/app/src/organisms/RunTimeControl/__fixtures__/index.ts +++ b/app/src/organisms/RunTimeControl/__fixtures__/index.ts @@ -41,6 +41,7 @@ export const mockPausedRun: RunData = { pipettes: [], labware: [], modules: [], + runTimeParameters: [], } export const mockPauseRequestedRun: RunData = { @@ -65,6 +66,7 @@ export const mockPauseRequestedRun: RunData = { pipettes: [], labware: [], modules: [], + runTimeParameters: [], } export const mockRunningRun: RunData = { @@ -94,6 +96,7 @@ export const mockRunningRun: RunData = { pipettes: [], labware: [], modules: [], + runTimeParameters: [], } export const mockFailedRun: RunData = { @@ -133,6 +136,7 @@ export const mockFailedRun: RunData = { pipettes: [], labware: [], modules: [], + runTimeParameters: [], } export const mockStopRequestedRun: RunData = { @@ -167,6 +171,7 @@ export const mockStopRequestedRun: RunData = { pipettes: [], labware: [], modules: [], + runTimeParameters: [], } export const mockStoppedRun: RunData = { @@ -201,6 +206,7 @@ export const mockStoppedRun: RunData = { pipettes: [], labware: [], modules: [], + runTimeParameters: [], } export const mockSucceededRun: RunData = { @@ -230,6 +236,7 @@ export const mockSucceededRun: RunData = { pipettes: [], labware: [], modules: [], + runTimeParameters: [], } export const mockIdleUnstartedRun: RunData = { @@ -243,6 +250,7 @@ export const mockIdleUnstartedRun: RunData = { pipettes: [], labware: [], modules: [], + runTimeParameters: [], } export const mockIdleStartedRun: RunData = { @@ -272,6 +280,7 @@ export const mockIdleStartedRun: RunData = { pipettes: [], labware: [], modules: [], + runTimeParameters: [], } export const mockCommand = { diff --git a/app/src/organisms/RunTimeControl/__tests__/hooks.test.tsx b/app/src/organisms/RunTimeControl/__tests__/hooks.test.tsx index 21adedbd165..a46bc37d865 100644 --- a/app/src/organisms/RunTimeControl/__tests__/hooks.test.tsx +++ b/app/src/organisms/RunTimeControl/__tests__/hooks.test.tsx @@ -61,7 +61,7 @@ describe('useRunControls hook', () => { isStopRunActionLoading: false, }) when(useCloneRun) - .calledWith(mockPausedRun.id, undefined) + .calledWith(mockPausedRun.id, undefined, true) .thenReturn({ cloneRun: mockCloneRun, isLoading: false }) const { result } = renderHook(() => useRunControls(mockPausedRun.id)) diff --git a/app/src/organisms/RunTimeControl/hooks.ts b/app/src/organisms/RunTimeControl/hooks.ts index c56f552b3ae..d513fcbe118 100644 --- a/app/src/organisms/RunTimeControl/hooks.ts +++ b/app/src/organisms/RunTimeControl/hooks.ts @@ -12,6 +12,7 @@ import { RUN_STATUS_SUCCEEDED, RUN_ACTION_TYPE_STOP, RUN_STATUS_STOP_REQUESTED, + RUN_STATUSES_TERMINAL, } from '@opentrons/api-client' import { useRunActionMutations } from '@opentrons/react-api-client' @@ -52,7 +53,8 @@ export function useRunControls( const { cloneRun, isLoading: isResetRunLoading } = useCloneRun( runId ?? null, - onCloneRunSuccess + onCloneRunSuccess, + true ) return { @@ -78,11 +80,7 @@ export function useRunStatus( refetchInterval: DEFAULT_STATUS_REFETCH_INTERVAL, enabled: lastRunStatus.current == null || - !([ - RUN_STATUS_FAILED, - RUN_STATUS_SUCCEEDED, - RUN_STATUS_STOPPED, - ] as RunStatus[]).includes(lastRunStatus.current), + !(RUN_STATUSES_TERMINAL as RunStatus[]).includes(lastRunStatus.current), onSuccess: data => (lastRunStatus.current = data?.data?.status ?? null), ...options, }) @@ -187,5 +185,6 @@ export function useRunErrors(runId: string | null): RunData['errors'] { export function useProtocolHasRunTimeParameters(runId: string | null): boolean { const mostRecentAnalysis = useMostRecentCompletedAnalysis(runId) - return mostRecentAnalysis?.runTimeParameters != null + const runTimeParameters = mostRecentAnalysis?.runTimeParameters ?? [] + return runTimeParameters.length > 0 } diff --git a/app/src/organisms/TakeoverModal/TakeoverModal.tsx b/app/src/organisms/TakeoverModal/TakeoverModal.tsx index 3dab071bdec..c87f33fc150 100644 --- a/app/src/organisms/TakeoverModal/TakeoverModal.tsx +++ b/app/src/organisms/TakeoverModal/TakeoverModal.tsx @@ -32,7 +32,7 @@ export function TakeoverModal(props: TakeoverModalProps): JSX.Element { confirmTerminate, terminateInProgress, } = props - const { i18n, t } = useTranslation('shared') + const { i18n, t } = useTranslation(['shared', 'branded']) const terminateHeader: ModalHeaderBaseProps = { title: t('terminate') + '?', @@ -46,7 +46,7 @@ export function TakeoverModal(props: TakeoverModalProps): JSX.Element { - {t('confirm_terminate')} + {t('branded:confirm_terminate')} - {t('computer_in_app_is_controlling_robot')} + {t('branded:computer_in_app_is_controlling_robot')} ) : null} {(downloading || downloaded) && error == null ? ( - + closeModal(true)} closeOnOutsideClick={true} footer={appUpdateFooter} @@ -191,7 +194,7 @@ export function UpdateAppModal(props: UpdateAppModalProps): JSX.Element { > - {t('update_requires_restarting')} + {t('branded:update_requires_restarting_app')} diff --git a/app/src/organisms/UpdateRobotBanner/index.tsx b/app/src/organisms/UpdateRobotBanner/index.tsx index ced443a2018..86e2201bf84 100644 --- a/app/src/organisms/UpdateRobotBanner/index.tsx +++ b/app/src/organisms/UpdateRobotBanner/index.tsx @@ -25,7 +25,7 @@ export function UpdateRobotBanner( props: UpdateRobotBannerProps ): JSX.Element | null { const { robot, ...styleProps } = props - const { t } = useTranslation('device_settings') + const { t } = useTranslation(['device_settings', 'branded']) const { autoUpdateAction } = useSelector((state: State) => { return getRobotUpdateDisplayInfo(state, robot?.name) @@ -40,7 +40,7 @@ export function UpdateRobotBanner( > - {t('robot_software_update_required')} + {t('branded:robot_software_update_required')} handleUpdateBuildroot(robot)} diff --git a/app/src/pages/AppSettings/GeneralSettings.tsx b/app/src/pages/AppSettings/GeneralSettings.tsx index 99bdf464d04..553f0e56356 100644 --- a/app/src/pages/AppSettings/GeneralSettings.tsx +++ b/app/src/pages/AppSettings/GeneralSettings.tsx @@ -54,7 +54,7 @@ const GITHUB_LINK = const ENABLE_APP_UPDATE_NOTIFICATIONS = 'Enable app update notifications' export function GeneralSettings(): JSX.Element { - const { t } = useTranslation(['app_settings', 'shared']) + const { t } = useTranslation(['app_settings', 'shared', 'branded']) const dispatch = useDispatch() const trackEvent = useTrackEvent() const [ @@ -113,7 +113,7 @@ export function GeneralSettings(): JSX.Element { type="warning" onCloseClick={() => setShowUpdateBanner(false)} > - {t('opentrons_app_update_available_variation')} + {t('branded:opentrons_app_update_available_variation')} - {t('versions_sync')} + {t('branded:versions_sync')} @@ -218,7 +218,7 @@ export function GeneralSettings(): JSX.Element { alignItems={ALIGN_CENTER} justifyContent={JUSTIFY_SPACE_BETWEEN} > - {t('receive_alert')} + {t('branded:receive_alert')} () const analyticsOptedIn = useSelector((s: State) => getAnalyticsOptedIn(s)) diff --git a/app/src/pages/ConnectViaUSB/index.tsx b/app/src/pages/ConnectViaUSB/index.tsx index 961da9b6092..72130c5444c 100644 --- a/app/src/pages/ConnectViaUSB/index.tsx +++ b/app/src/pages/ConnectViaUSB/index.tsx @@ -22,7 +22,7 @@ import { StepMeter } from '../../atoms/StepMeter' import { MediumButton } from '../../atoms/buttons' export function ConnectViaUSB(): JSX.Element { - const { i18n, t } = useTranslation(['device_settings', 'shared']) + const { i18n, t } = useTranslation(['device_settings', 'shared', 'branded']) const history = useHistory() // TODO(bh, 2023-5-31): active connections from /system/connected isn't exactly the right way to monitor for a usb connection - // the system-server tracks active connections by authorization token, which is valid for 2 hours @@ -92,7 +92,7 @@ export function ConnectViaUSB(): JSX.Element { color={COLORS.grey60} textAlign={TYPOGRAPHY.textAlignCenter} > - {t('find_your_robot')} + {t('branded:find_your_robot')} @@ -134,7 +134,7 @@ export function ConnectViaUSB(): JSX.Element { {t('connect_via_usb_description_2')} - {t('connect_via_usb_description_3')} + {t('branded:connect_via_usb_description_3')} diff --git a/app/src/pages/DeckConfiguration/__tests__/DeckConfiguration.test.tsx b/app/src/pages/DeckConfiguration/__tests__/DeckConfiguration.test.tsx index 79bfa476960..9efe3bc0aa2 100644 --- a/app/src/pages/DeckConfiguration/__tests__/DeckConfiguration.test.tsx +++ b/app/src/pages/DeckConfiguration/__tests__/DeckConfiguration.test.tsx @@ -1,23 +1,21 @@ import * as React from 'react' import { MemoryRouter } from 'react-router-dom' import { vi, it, describe, expect, beforeEach } from 'vitest' +import { fireEvent, screen } from '@testing-library/react' import { DeckConfigurator } from '@opentrons/components' import { renderWithProviders } from '../../../__testing-utils__' -import { - useDeckConfigurationQuery, - useUpdateDeckConfigurationMutation, -} from '@opentrons/react-api-client' +import { useUpdateDeckConfigurationMutation } from '@opentrons/react-api-client' import { TRASH_BIN_ADAPTER_FIXTURE } from '@opentrons/shared-data' import { i18n } from '../../../i18n' import { DeckFixtureSetupInstructionsModal } from '../../../organisms/DeviceDetailsDeckConfiguration/DeckFixtureSetupInstructionsModal' import { DeckConfigurationEditor } from '..' +import { useNotifyDeckConfigurationQuery } from '../../../resources/deck_configuration' import type { UseQueryResult } from 'react-query' import type { DeckConfiguration } from '@opentrons/shared-data' -import { fireEvent, screen } from '@testing-library/react' import type * as Components from '@opentrons/components' import type * as ReactRouterDom from 'react-router-dom' @@ -52,6 +50,7 @@ vi.mock( vi.mock( '../../../organisms/DeviceDetailsDeckConfiguration/DeckConfigurationDiscardChangesModal' ) +vi.mock('../../../resources/deck_configuration') const render = () => { return renderWithProviders( @@ -66,7 +65,7 @@ const render = () => { describe('DeckConfigurationEditor', () => { beforeEach(() => { - vi.mocked(useDeckConfigurationQuery).mockReturnValue({ + vi.mocked(useNotifyDeckConfigurationQuery).mockReturnValue({ data: mockDeckConfig, } as UseQueryResult) vi.mocked(useUpdateDeckConfigurationMutation).mockReturnValue({ diff --git a/app/src/pages/DeckConfiguration/index.tsx b/app/src/pages/DeckConfiguration/index.tsx index d2e5b508325..2c90d5249b8 100644 --- a/app/src/pages/DeckConfiguration/index.tsx +++ b/app/src/pages/DeckConfiguration/index.tsx @@ -11,14 +11,15 @@ import { JUSTIFY_CENTER, JUSTIFY_SPACE_AROUND, } from '@opentrons/components' -import { - useDeckConfigurationQuery, - useUpdateDeckConfigurationMutation, -} from '@opentrons/react-api-client' +import { useUpdateDeckConfigurationMutation } from '@opentrons/react-api-client' import { SINGLE_RIGHT_CUTOUTS, SINGLE_LEFT_SLOT_FIXTURE, SINGLE_RIGHT_SLOT_FIXTURE, + SINGLE_LEFT_CUTOUTS, + SINGLE_CENTER_SLOT_FIXTURE, + getDeckDefFromRobotType, + FLEX_ROBOT_TYPE, } from '@opentrons/shared-data' import { SmallButton } from '../../atoms/buttons' @@ -27,8 +28,13 @@ import { AddFixtureModal } from '../../organisms/DeviceDetailsDeckConfiguration/ import { DeckFixtureSetupInstructionsModal } from '../../organisms/DeviceDetailsDeckConfiguration/DeckFixtureSetupInstructionsModal' import { DeckConfigurationDiscardChangesModal } from '../../organisms/DeviceDetailsDeckConfiguration/DeckConfigurationDiscardChangesModal' import { getTopPortalEl } from '../../App/portal' +import { useNotifyDeckConfigurationQuery } from '../../resources/deck_configuration' -import type { CutoutId, DeckConfiguration } from '@opentrons/shared-data' +import type { + CutoutFixtureId, + CutoutId, + DeckConfiguration, +} from '@opentrons/shared-data' export function DeckConfigurationEditor(): JSX.Element { const { t, i18n } = useTranslation([ @@ -53,7 +59,8 @@ export function DeckConfigurationEditor(): JSX.Element { setShowDiscardChangeModal, ] = React.useState(false) - const deckConfig = useDeckConfigurationQuery().data ?? [] + const deckDef = getDeckDefFromRobotType(FLEX_ROBOT_TYPE) + const deckConfig = useNotifyDeckConfigurationQuery().data ?? [] const { updateDeckConfiguration } = useUpdateDeckConfigurationMutation() const [ @@ -66,19 +73,53 @@ export function DeckConfigurationEditor(): JSX.Element { setShowConfigurationModal(true) } - const handleClickRemove = (cutoutId: CutoutId): void => { - setCurrentDeckConfig(prevDeckConfig => - prevDeckConfig.map(fixture => - fixture.cutoutId === cutoutId + const handleClickRemove = ( + cutoutId: CutoutId, + cutoutFixtureId: CutoutFixtureId + ): void => { + let replacementFixtureId: CutoutFixtureId = SINGLE_CENTER_SLOT_FIXTURE + if (SINGLE_RIGHT_CUTOUTS.includes(cutoutId)) { + replacementFixtureId = SINGLE_RIGHT_SLOT_FIXTURE + } else if (SINGLE_LEFT_CUTOUTS.includes(cutoutId)) { + replacementFixtureId = SINGLE_LEFT_SLOT_FIXTURE + } + + const fixtureGroup = + deckDef.cutoutFixtures.find(cf => cf.id === cutoutFixtureId) + ?.fixtureGroup ?? {} + + let newDeckConfig = currentDeckConfig + if (cutoutId in fixtureGroup) { + const groupMap = + fixtureGroup[cutoutId]?.find(group => + Object.entries(group).every(([cId, cfId]) => + currentDeckConfig.find( + config => + config.cutoutId === cId && config.cutoutFixtureId === cfId + ) + ) + ) ?? {} + newDeckConfig = currentDeckConfig.map(cutoutConfig => + cutoutConfig.cutoutId in groupMap ? { - ...fixture, - cutoutFixtureId: SINGLE_RIGHT_CUTOUTS.includes(cutoutId) - ? SINGLE_RIGHT_SLOT_FIXTURE - : SINGLE_LEFT_SLOT_FIXTURE, + ...cutoutConfig, + cutoutFixtureId: replacementFixtureId, + opentronsModuleSerialNumber: undefined, } - : fixture + : cutoutConfig ) - ) + } else { + newDeckConfig = currentDeckConfig.map(cutoutConfig => + cutoutConfig.cutoutId === cutoutId + ? { + ...cutoutConfig, + cutoutFixtureId: replacementFixtureId, + opentronsModuleSerialNumber: undefined, + } + : cutoutConfig + ) + } + setCurrentDeckConfig(newDeckConfig) } const handleClickConfirm = (): void => { diff --git a/app/src/pages/InitialLoadingScreen/__tests__/InitialLoadingScreen.test.tsx b/app/src/pages/InitialLoadingScreen/__tests__/InitialLoadingScreen.test.tsx index 940c7694c54..a7e9076bb63 100644 --- a/app/src/pages/InitialLoadingScreen/__tests__/InitialLoadingScreen.test.tsx +++ b/app/src/pages/InitialLoadingScreen/__tests__/InitialLoadingScreen.test.tsx @@ -2,33 +2,31 @@ import * as React from 'react' import { vi, it, describe, beforeEach, afterEach } from 'vitest' import { screen } from '@testing-library/react' +import { useRobotSettingsQuery } from '@opentrons/react-api-client' + import { renderWithProviders } from '../../../__testing-utils__' -import { getOnDeviceDisplaySettings } from '../../../redux/config' import { getIsShellReady } from '../../../redux/shell' import { InitialLoadingScreen } from '..' -import type { OnDeviceDisplaySettings } from '../../../redux/config/schema-types' +import type { UseQueryResult } from 'react-query' +import type { RobotSettingsResponse } from '@opentrons/api-client' +vi.mock('@opentrons/react-api-client') vi.mock('../../../redux/config') vi.mock('../../../redux/shell') -const mockSettings = { - sleepMs: 60 * 1000 * 60 * 24 * 7, - brightness: 4, - textSize: 1, - unfinishedUnboxingFlowRoute: null, -} as OnDeviceDisplaySettings - const render = () => { return renderWithProviders() } describe('InitialLoadingScreen', () => { beforeEach(() => { - vi.mocked(getOnDeviceDisplaySettings).mockReturnValue(mockSettings) vi.mocked(getIsShellReady).mockReturnValue(false) + vi.mocked(useRobotSettingsQuery).mockReturnValue(({ + data: { settings: [] }, + } as unknown) as UseQueryResult) }) afterEach(() => { diff --git a/app/src/pages/InitialLoadingScreen/index.tsx b/app/src/pages/InitialLoadingScreen/index.tsx index 5171b2720b3..d57519bfa3b 100644 --- a/app/src/pages/InitialLoadingScreen/index.tsx +++ b/app/src/pages/InitialLoadingScreen/index.tsx @@ -1,5 +1,4 @@ import * as React from 'react' -import { Redirect } from 'react-router-dom' import { useSelector } from 'react-redux' import { ALIGN_CENTER, @@ -10,30 +9,23 @@ import { JUSTIFY_CENTER, SPACING, } from '@opentrons/components' -import { getOnDeviceDisplaySettings } from '../../redux/config' +import { useRobotSettingsQuery } from '@opentrons/react-api-client' import { getIsShellReady } from '../../redux/shell' -const getTargetPath = ( - isShellReady: boolean, - unfinishedUnboxingFlowRoute: string | null -): string | null => { - if (!isShellReady) { - return null - } - if (unfinishedUnboxingFlowRoute != null) { - return unfinishedUnboxingFlowRoute - } - - return '/dashboard' -} -export function InitialLoadingScreen(): JSX.Element { - const { unfinishedUnboxingFlowRoute } = useSelector( - getOnDeviceDisplaySettings - ) +export function InitialLoadingScreen({ + children, +}: { + children?: React.ReactNode +}): JSX.Element { const isShellReady = useSelector(getIsShellReady) - const targetPath = getTargetPath(isShellReady, unfinishedUnboxingFlowRoute) - return ( + // ensure robot-server api is up and settings query data available for localization provider + const { settings } = + useRobotSettingsQuery({ retry: true, retryDelay: 1000 }).data ?? {} + + return isShellReady && settings != null ? ( + <>{children} + ) : ( - {targetPath != null && } ) } diff --git a/app/src/pages/InstrumentDetail/__tests__/InstrumentDetail.test.tsx b/app/src/pages/InstrumentDetail/__tests__/InstrumentDetail.test.tsx index 56f1c4a11b3..0743afedbe1 100644 --- a/app/src/pages/InstrumentDetail/__tests__/InstrumentDetail.test.tsx +++ b/app/src/pages/InstrumentDetail/__tests__/InstrumentDetail.test.tsx @@ -4,30 +4,24 @@ import { useParams } from 'react-router-dom' import { useInstrumentsQuery } from '@opentrons/react-api-client' import { renderWithProviders } from '../../../__testing-utils__' -import { - getPipetteModelSpecs, - getGripperDisplayName, -} from '@opentrons/shared-data' import { i18n } from '../../../i18n' import { InstrumentDetail } from '../../../pages/InstrumentDetail' +import { + useGripperDisplayName, + usePipetteModelSpecs, +} from '../../../resources/instruments/hooks' +import { useIsOEMMode } from '../../../resources/robot-settings/hooks' import type { Instruments } from '@opentrons/api-client' -import type * as SharedData from '@opentrons/shared-data' vi.mock('@opentrons/react-api-client') -vi.mock('@opentrons/shared-data', async importOriginal => { - const actual = await importOriginal() - return { - ...actual, - getPipetteModelSpecs: vi.fn(), - getGripperDisplayName: vi.fn(), - } -}) vi.mock('react-router-dom', () => ({ useParams: vi.fn(), useHistory: vi.fn(), })) +vi.mock('../../../resources/instruments/hooks') +vi.mock('../../../resources/robot-settings/hooks') const render = () => { return renderWithProviders(, { @@ -97,11 +91,12 @@ describe('InstrumentDetail', () => { vi.mocked(useInstrumentsQuery).mockReturnValue({ data: mockInstrumentsQuery, } as any) - vi.mocked(getPipetteModelSpecs).mockReturnValue({ + vi.mocked(usePipetteModelSpecs).mockReturnValue({ displayName: 'mockPipette', } as any) - vi.mocked(getGripperDisplayName).mockReturnValue('mockGripper') + vi.mocked(useGripperDisplayName).mockReturnValue('mockGripper') vi.mocked(useParams).mockReturnValue({ mount: 'left' }) + vi.mocked(useIsOEMMode).mockReturnValue(false) }) afterEach(() => { diff --git a/app/src/pages/InstrumentDetail/index.tsx b/app/src/pages/InstrumentDetail/index.tsx index 6bf5ddc8433..cececd01703 100644 --- a/app/src/pages/InstrumentDetail/index.tsx +++ b/app/src/pages/InstrumentDetail/index.tsx @@ -2,12 +2,6 @@ import * as React from 'react' import { useParams } from 'react-router-dom' import styled from 'styled-components' -import { - getGripperDisplayName, - getPipetteModelSpecs, - GripperModel, - PipetteModel, -} from '@opentrons/shared-data' import { useInstrumentsQuery, useHost } from '@opentrons/react-api-client' import { Icon, @@ -21,11 +15,16 @@ import { } from '@opentrons/components' import { BackButton } from '../../atoms/buttons/BackButton' +import { ODD_FOCUS_VISIBLE } from '../../atoms/buttons/constants' import { InstrumentInfo } from '../../organisms/InstrumentInfo' import { handleInstrumentDetailOverflowMenu } from '../../pages/InstrumentDetail/InstrumentDetailOverflowMenu' -import { ODD_FOCUS_VISIBLE } from '../../atoms/buttons/constants' +import { + useGripperDisplayName, + usePipetteModelSpecs, +} from '../../resources/instruments/hooks' import type { GripperData, PipetteData } from '@opentrons/api-client' +import type { GripperModel, PipetteModel } from '@opentrons/shared-data' export const InstrumentDetail = (): JSX.Element => { const host = useHost() @@ -36,11 +35,15 @@ export const InstrumentDetail = (): JSX.Element => { (i): i is PipetteData | GripperData => i.ok && i.mount === mount ) ?? null + const pipetteDisplayName = usePipetteModelSpecs( + instrument?.instrumentModel as PipetteModel + )?.displayName + const gripperDisplayName = useGripperDisplayName( + instrument?.instrumentModel as GripperModel + ) + const displayName = - instrument?.mount !== 'extension' - ? getPipetteModelSpecs(instrument?.instrumentModel as PipetteModel) - ?.displayName - : getGripperDisplayName(instrument?.instrumentModel as GripperModel) + instrument?.mount !== 'extension' ? pipetteDisplayName : gripperDisplayName return ( <> diff --git a/app/src/pages/InstrumentsDashboard/__tests__/InstrumentsDashboard.test.tsx b/app/src/pages/InstrumentsDashboard/__tests__/InstrumentsDashboard.test.tsx index d816731eea1..06e040bbe39 100644 --- a/app/src/pages/InstrumentsDashboard/__tests__/InstrumentsDashboard.test.tsx +++ b/app/src/pages/InstrumentsDashboard/__tests__/InstrumentsDashboard.test.tsx @@ -14,7 +14,7 @@ import { InstrumentDetail } from '../../../pages/InstrumentDetail' import type * as ReactApiClient from '@opentrons/react-api-client' const mockGripperData = { - instrumentModel: 'gripper_v1', + instrumentModel: 'gripperV1', instrumentType: 'gripper', mount: 'extension', serialNumber: 'ghi789', diff --git a/app/src/pages/Labware/hooks.tsx b/app/src/pages/Labware/hooks.tsx index caf37544be5..b1453738652 100644 --- a/app/src/pages/Labware/hooks.tsx +++ b/app/src/pages/Labware/hooks.tsx @@ -69,7 +69,7 @@ export function useLabwareFailure(): { labwareFailureMessage: string | null clearLabwareFailure: () => unknown } { - const { t } = useTranslation('labware_landing') + const { t } = useTranslation(['labware_landing', 'branded']) const dispatch = useDispatch() const labwareFailure = useSelector(getAddLabwareFailure) @@ -82,7 +82,7 @@ export function useLabwareFailure(): { } else if (failedFile?.type === 'DUPLICATE_LABWARE_FILE') { errorMessage = t('duplicate_labware_def') } else if (failedFile?.type === 'OPENTRONS_LABWARE_FILE') { - errorMessage = t('opentrons_labware_def') + errorMessage = t('branded:opentrons_labware_def') } labwareFailureMessage = failedFile != null diff --git a/app/src/pages/NetworkSetupMenu/index.tsx b/app/src/pages/NetworkSetupMenu/index.tsx index 7250eaa3dda..11909bdb77f 100644 --- a/app/src/pages/NetworkSetupMenu/index.tsx +++ b/app/src/pages/NetworkSetupMenu/index.tsx @@ -34,13 +34,13 @@ const NetworkSetupOptions = [ { title: 'usb', iconName: 'usb' as IconName, - description: 'connection_description_usb', + description: 'branded:connection_description_usb', destinationPath: '/network-setup/usb', }, ] export function NetworkSetupMenu(): JSX.Element { - const { t } = useTranslation('device_settings') + const { t } = useTranslation(['device_settings', 'branded']) return ( <> @@ -73,7 +73,7 @@ export function NetworkSetupMenu(): JSX.Element { color={COLORS.grey60} textAlign={TYPOGRAPHY.textAlignCenter} > - {t('network_setup_menu_description')} + {t('branded:network_setup_menu_description')}
- {t('send_a_protocol_to_store')} + {t('branded:send_a_protocol_to_store')} ) diff --git a/app/src/pages/ProtocolDashboard/ProtocolCard.tsx b/app/src/pages/ProtocolDashboard/ProtocolCard.tsx index 1ed35b8632f..305ca99c7bc 100644 --- a/app/src/pages/ProtocolDashboard/ProtocolCard.tsx +++ b/app/src/pages/ProtocolDashboard/ProtocolCard.tsx @@ -60,7 +60,7 @@ export function ProtocolCard(props: { showFailedAnalysisModal, setShowFailedAnalysisModal, ] = React.useState(false) - const { t, i18n } = useTranslation('protocol_info') + const { t, i18n } = useTranslation(['protocol_info', 'branded']) const protocolName = protocol.metadata.protocolName ?? protocol.files[0].name const longpress = useLongPress() const queryClient = useQueryClient() @@ -264,7 +264,9 @@ export function ProtocolCard(props: { }} /> - {t('delete_protocol_from_app')} + + {t('branded:delete_protocol_from_app')} +
() const [navMenuIsOpened, setNavMenuIsOpened] = React.useState(false) @@ -58,6 +60,9 @@ export function ProtocolDashboard(): JSX.Element { const pinnedProtocolIds = useSelector(getPinnedProtocolIds) ?? [] const pinnedProtocols: ProtocolResource[] = [] + // TODO(sb, 4/15/24): The quick transfer button is going to be moved to a new quick transfer + // tab before the feature is released. Because of this, we're not adding test cov + // for this button in ProtocolDashboard const enableQuickTransferFF = useFeatureFlag('enableQuickTransfer') // We only need to grab out the pinned protocol data once all the protocols load @@ -181,7 +186,6 @@ export function ProtocolDashboard(): JSX.Element { backgroundColor={COLORS.white} flexDirection={DIRECTION_ROW} paddingBottom={SPACING.spacing16} - paddingTop={SPACING.spacing16} position={ navMenuIsOpened || longPressModalIsOpened ? POSITION_STATIC @@ -280,7 +284,7 @@ export function ProtocolDashboard(): JSX.Element { buttonText={t('quick_transfer')} iconName="plus" onClick={() => { - console.log('launch quick transfer flow') + history.push('/quick-transfer') }} /> )} diff --git a/app/src/pages/ProtocolDetails/Hardware.tsx b/app/src/pages/ProtocolDetails/Hardware.tsx index da6d1f2633c..c59c24e7118 100644 --- a/app/src/pages/ProtocolDetails/Hardware.tsx +++ b/app/src/pages/ProtocolDetails/Hardware.tsx @@ -14,18 +14,21 @@ import { WRAP, } from '@opentrons/components' import { - GRIPPER_V1, getCutoutDisplayName, - getGripperDisplayName, getModuleDisplayName, getModuleType, - getPipetteNameSpecs, getFixtureDisplayName, + GRIPPER_V1_2, } from '@opentrons/shared-data' + +import { + useGripperDisplayName, + usePipetteNameSpecs, +} from '../../resources/instruments/hooks' import { useRequiredProtocolHardware } from '../Protocols/hooks' import { EmptySection } from './EmptySection' -import type { ProtocolHardware } from '../Protocols/hooks' +import type { ProtocolHardware, ProtocolPipette } from '../Protocols/hooks' import type { TFunction } from 'i18next' const Table = styled('table')` @@ -75,11 +78,19 @@ const getHardwareLocation = ( } } -const getHardwareName = (protocolHardware: ProtocolHardware): string => { +// convert to anon + +const useHardwareName = (protocolHardware: ProtocolHardware): string => { + const gripperDisplayName = useGripperDisplayName(GRIPPER_V1_2) + + const pipetteDisplayName = + usePipetteNameSpecs((protocolHardware as ProtocolPipette).pipetteName) + ?.displayName ?? '' + if (protocolHardware.hardwareType === 'gripper') { - return getGripperDisplayName(GRIPPER_V1) + return gripperDisplayName } else if (protocolHardware.hardwareType === 'pipette') { - return getPipetteNameSpecs(protocolHardware.pipetteName)?.displayName ?? '' + return pipetteDisplayName } else if (protocolHardware.hardwareType === 'module') { return getModuleDisplayName(protocolHardware.moduleModel) } else { @@ -87,6 +98,54 @@ const getHardwareName = (protocolHardware: ProtocolHardware): string => { } } +function HardwareItem({ + hardware, +}: { + hardware: ProtocolHardware +}): JSX.Element { + const { t, i18n } = useTranslation('protocol_details') + + const hardwareName = useHardwareName(hardware) + + let location: JSX.Element = ( + + {i18n.format(getHardwareLocation(hardware, t), 'titleCase')} + + ) + if (hardware.hardwareType === 'module') { + location = + } else if (hardware.hardwareType === 'fixture') { + location = ( + + ) + } + return ( + + + {location} + + + + {hardware.hardwareType === 'module' && ( + + + + )} + {hardwareName} + + + + ) +} + export const Hardware = (props: { protocolId: string }): JSX.Element => { const { requiredProtocolHardware } = useRequiredProtocolHardware( props.protocolId @@ -123,45 +182,7 @@ export const Hardware = (props: { protocolId: string }): JSX.Element => { {requiredProtocolHardware.map((hardware, id) => { - let location: JSX.Element = ( - - {i18n.format(getHardwareLocation(hardware, t), 'titleCase')} - - ) - if (hardware.hardwareType === 'module') { - location = - } else if (hardware.hardwareType === 'fixture') { - location = ( - - ) - } - return ( - - - {location} - - - - {hardware.hardwareType === 'module' && ( - - - - )} - {getHardwareName(hardware)} - - - - ) + return })} diff --git a/app/src/pages/ProtocolDetails/fixtures.ts b/app/src/pages/ProtocolDetails/fixtures.ts index d1752853bda..dd23bc4623e 100644 --- a/app/src/pages/ProtocolDetails/fixtures.ts +++ b/app/src/pages/ProtocolDetails/fixtures.ts @@ -14,7 +14,7 @@ export const mockRunTimeParameterData: RunTimeParameter[] = [ variableName: 'USE_GRIPPER', description: '', type: 'bool', - default: true, + default: false, value: true, }, { diff --git a/app/src/pages/ProtocolDetails/index.tsx b/app/src/pages/ProtocolDetails/index.tsx index 0503c0eae54..850fd0a8016 100644 --- a/app/src/pages/ProtocolDetails/index.tsx +++ b/app/src/pages/ProtocolDetails/index.tsx @@ -346,13 +346,12 @@ export function ProtocolDetails(): JSX.Element | null { let pinnedProtocolIds = useSelector(getPinnedProtocolIds) ?? [] const pinned = pinnedProtocolIds.includes(protocolId) - const { data: protocolData } = useProtocolQuery(protocolId) const { data: mostRecentAnalysis, } = useProtocolAnalysisAsDocumentQuery( protocolId, - last(protocolData?.data.analysisSummaries)?.id ?? null, - { enabled: protocolData != null } + last(protocolRecord?.data.analysisSummaries)?.id ?? null, + { enabled: protocolRecord != null } ) const shouldApplyOffsets = useSelector(getApplyHistoricOffsets) diff --git a/app/src/pages/ProtocolSetup/__tests__/ProtocolSetup.test.tsx b/app/src/pages/ProtocolSetup/__tests__/ProtocolSetup.test.tsx index b4b5af7e0c8..32bc9963d0a 100644 --- a/app/src/pages/ProtocolSetup/__tests__/ProtocolSetup.test.tsx +++ b/app/src/pages/ProtocolSetup/__tests__/ProtocolSetup.test.tsx @@ -11,7 +11,6 @@ import { useProtocolQuery, useDoorQuery, useModulesQuery, - useDeckConfigurationQuery, useProtocolAnalysisAsDocumentQuery, } from '@opentrons/react-api-client' import { renderWithProviders } from '../../../__testing-utils__' @@ -20,7 +19,7 @@ import { getDeckDefFromRobotType, FLEX_ROBOT_TYPE, STAGING_AREA_RIGHT_SLOT_FIXTURE, - flexDeckDefV4, + flexDeckDefV5, } from '@opentrons/shared-data' import { i18n } from '../../../i18n' @@ -35,7 +34,7 @@ import { useTrackProtocolRunEvent, } from '../../../organisms/Devices/hooks' import { getLocalRobot } from '../../../redux/discovery' -import { ANALYTICS_PROTOCOL_RUN_START } from '../../../redux/analytics' +import { ANALYTICS_PROTOCOL_RUN_ACTION } from '../../../redux/analytics' import { ProtocolSetupLiquids } from '../../../organisms/ProtocolSetupLiquids' import { getProtocolModulesInfo } from '../../../organisms/Devices/ProtocolRun/utils/getProtocolModulesInfo' import { ProtocolSetupModulesAndDeck } from '../../../organisms/ProtocolSetupModulesAndDeck' @@ -57,6 +56,7 @@ import { useFeatureFlag } from '../../../redux/config' import { ViewOnlyParameters } from '../../../organisms/ProtocolSetupParameters/ViewOnlyParameters' import { mockConnectableRobot } from '../../../redux/discovery/__fixtures__' import { mockRunTimeParameterData } from '../../ProtocolDetails/fixtures' +import { useNotifyDeckConfigurationQuery } from '../../../resources/deck_configuration' import type { UseQueryResult } from 'react-query' import type * as SharedData from '@opentrons/shared-data' @@ -114,6 +114,7 @@ vi.mock('../ConfirmAttachedModal') vi.mock('../../../organisms/ToasterOven') vi.mock('../../../resources/deck_configuration/hooks') vi.mock('../../../resources/runs') +vi.mock('../../../resources/deck_configuration') const render = (path = '/') => { return renderWithProviders( @@ -229,14 +230,14 @@ describe('ProtocolSetup', () => { .calledWith(RUN_ID) .thenReturn(CREATED_AT) when(vi.mocked(getProtocolModulesInfo)) - .calledWith(mockEmptyAnalysis, flexDeckDefV4 as any) + .calledWith(mockEmptyAnalysis, flexDeckDefV5 as any) .thenReturn([]) when(vi.mocked(getUnmatchedModulesForProtocol)) .calledWith([], []) .thenReturn({ missingModuleIds: [], remainingAttachedModules: [] }) when(vi.mocked(getDeckDefFromRobotType)) .calledWith('OT-3 Standard') - .thenReturn(flexDeckDefV4 as any) + .thenReturn(flexDeckDefV5 as any) when(vi.mocked(useNotifyRunQuery)) .calledWith(RUN_ID, { staleTime: Infinity }) .thenReturn({ @@ -273,7 +274,7 @@ describe('ProtocolSetup', () => { vi.mocked(useModulesQuery).mockReturnValue({ data: { data: [mockHeaterShaker] }, } as any) - vi.mocked(useDeckConfigurationQuery).mockReturnValue({ + vi.mocked(useNotifyDeckConfigurationQuery).mockReturnValue({ data: [mockFixture], } as UseQueryResult) when(vi.mocked(useToaster)) @@ -296,7 +297,7 @@ describe('ProtocolSetup', () => { render(`/runs/${RUN_ID}/setup/`) screen.getByText('Prepare to run') screen.getByText('Instruments') - screen.getByText('Modules & deck') + screen.getByText('Deck hardware') screen.getByText('Labware') screen.getByText('Labware Position Check') screen.getByText('Liquids') @@ -320,13 +321,13 @@ describe('ProtocolSetup', () => { data: mockRobotSideAnalysis, } as any) when(vi.mocked(getProtocolModulesInfo)) - .calledWith(mockRobotSideAnalysis, flexDeckDefV4 as any) + .calledWith(mockRobotSideAnalysis, flexDeckDefV5 as any) .thenReturn(mockProtocolModuleInfo) when(vi.mocked(getUnmatchedModulesForProtocol)) .calledWith([], mockProtocolModuleInfo) .thenReturn({ missingModuleIds: [], remainingAttachedModules: [] }) render(`/runs/${RUN_ID}/setup/`) - fireEvent.click(screen.getByText('Modules & deck')) + fireEvent.click(screen.getByText('Deck hardware')) expect(vi.mocked(ProtocolSetupModulesAndDeck)).toHaveBeenCalled() }) @@ -337,7 +338,7 @@ describe('ProtocolSetup', () => { when(vi.mocked(getProtocolModulesInfo)) .calledWith( { ...mockRobotSideAnalysis, liquids: mockLiquids }, - flexDeckDefV4 as any + flexDeckDefV5 as any ) .thenReturn(mockProtocolModuleInfo) when(vi.mocked(getUnmatchedModulesForProtocol)) @@ -364,7 +365,7 @@ describe('ProtocolSetup', () => { ...mockRobotSideAnalysis, runTimeParameters: mockRunTimeParameterData, }, - flexDeckDefV4 as any + flexDeckDefV5 as any ) .thenReturn(mockProtocolModuleInfo) when(vi.mocked(getUnmatchedModulesForProtocol)) @@ -419,7 +420,7 @@ describe('ProtocolSetup', () => { fireEvent.click(screen.getByRole('button', { name: 'play' })) expect(mockTrackProtocolRunEvent).toBeCalledTimes(1) expect(mockTrackProtocolRunEvent).toHaveBeenCalledWith({ - name: ANALYTICS_PROTOCOL_RUN_START, + name: ANALYTICS_PROTOCOL_RUN_ACTION.START, properties: {}, }) }) diff --git a/app/src/pages/ProtocolSetup/index.tsx b/app/src/pages/ProtocolSetup/index.tsx index f2fb24feaa5..1818493e7d0 100644 --- a/app/src/pages/ProtocolSetup/index.tsx +++ b/app/src/pages/ProtocolSetup/index.tsx @@ -69,7 +69,6 @@ import { getProtocolUsesGripper, } from '../../organisms/ProtocolSetupInstruments/utils' import { - useProtocolHasRunTimeParameters, useRunControls, useRunStatus, } from '../../organisms/RunTimeControl/hooks' @@ -79,7 +78,7 @@ import { getLabwareSetupItemGroups } from '../Protocols/utils' import { getLocalRobot, getRobotSerialNumber } from '../../redux/discovery' import { ANALYTICS_PROTOCOL_PROCEED_TO_RUN, - ANALYTICS_PROTOCOL_RUN_START, + ANALYTICS_PROTOCOL_RUN_ACTION, useTrackEvent, } from '../../redux/analytics' import { getIsHeaterShakerAttached } from '../../redux/config' @@ -257,8 +256,6 @@ function PrepareToRun({ const { t, i18n } = useTranslation(['protocol_setup', 'shared']) const history = useHistory() const { makeSnackbar } = useToaster() - const hasRunTimeParameters = useProtocolHasRunTimeParameters(runId) - // Watch for scrolling to toggle dropshadow const scrollRef = React.useRef(null) const [isScrolled, setIsScrolled] = React.useState(false) const observer = new IntersectionObserver(([entry]) => { @@ -365,6 +362,12 @@ function PrepareToRun({ }) const moduleCalibrationStatus = useModuleCalibrationStatus(robotName, runId) + const runTimeParameters = mostRecentAnalysis?.runTimeParameters ?? [] + const hasRunTimeParameters = runTimeParameters.length > 0 + const hasCustomRunTimeParameters = runTimeParameters.some( + parameter => parameter.value !== parameter.default + ) + const [ showConfirmCancelModal, setShowConfirmCancelModal, @@ -489,7 +492,7 @@ function PrepareToRun({ if (isReadyToRun) { play() trackProtocolRunEvent({ - name: ANALYTICS_PROTOCOL_RUN_START, + name: ANALYTICS_PROTOCOL_RUN_ACTION.START, properties: robotAnalyticsData != null ? robotAnalyticsData : {}, }) } else { @@ -622,11 +625,11 @@ function PrepareToRun({ doorStatus?.data.status === 'open' && doorStatus?.data.doorRequiredClosedForProtocol - // TODO(Jr, 3/20/24): wire up custom values - const hasCustomValues = false - const parametersDetail = hasCustomValues - ? t('custom_values') - : t('default_values') + const parametersDetail = hasRunTimeParameters + ? hasCustomRunTimeParameters + ? t('custom_values') + : t('default_values') + : t('no_parameters_specified') return ( <> @@ -702,7 +705,7 @@ function PrepareToRun({ /> setSetupScreen('modules')} - title={t('modules_and_deck')} + title={t('deck_hardware')} detail={modulesDetail} subDetail={modulesSubDetail} status={modulesStatus} @@ -732,11 +735,7 @@ function PrepareToRun({ setSetupScreen('view only parameters')} title={t('parameters')} - detail={t( - hasRunTimeParameters - ? parametersDetail - : t('no_parameters_specified') - )} + detail={parametersDetail} subDetail={null} status="general" disabled={!hasRunTimeParameters} diff --git a/app/src/pages/Protocols/hooks/__tests__/hooks.test.tsx b/app/src/pages/Protocols/hooks/__tests__/hooks.test.tsx index aa8d9f07e8a..79e0e16a759 100644 --- a/app/src/pages/Protocols/hooks/__tests__/hooks.test.tsx +++ b/app/src/pages/Protocols/hooks/__tests__/hooks.test.tsx @@ -9,7 +9,6 @@ import { useProtocolAnalysisAsDocumentQuery, useInstrumentsQuery, useModulesQuery, - useDeckConfigurationQuery, } from '@opentrons/react-api-client' import { CompletedProtocolAnalysis, @@ -24,6 +23,7 @@ import { useRequiredProtocolLabware, useRunTimeParameters, } from '../index' +import { useNotifyDeckConfigurationQuery } from '../../../../resources/deck_configuration/useNotifyDeckConfigurationQuery' import type { Protocol } from '@opentrons/api-client' import { mockHeaterShaker } from '../../../../redux/modules/__fixtures__' @@ -31,6 +31,9 @@ import { mockHeaterShaker } from '../../../../redux/modules/__fixtures__' vi.mock('@opentrons/react-api-client') vi.mock('../../../../organisms/Devices/hooks') vi.mock('../../../../redux/config') +vi.mock( + '../../../../resources/deck_configuration/useNotifyDeckConfigurationQuery' +) const PROTOCOL_ID = 'fake_protocol_id' const mockRTPData = [ @@ -261,7 +264,7 @@ describe('useRequiredProtocolLabware', () => { }) }) -describe('useMissingProtocolHardware', () => { +describe.only('useMissingProtocolHardware', () => { let wrapper: React.FunctionComponent<{ children: React.ReactNode }> beforeEach(() => { vi.mocked(useInstrumentsQuery).mockReturnValue({ @@ -280,7 +283,7 @@ describe('useMissingProtocolHardware', () => { vi.mocked(useProtocolAnalysisAsDocumentQuery).mockReturnValue({ data: PROTOCOL_ANALYSIS, } as UseQueryResult) - vi.mocked(useDeckConfigurationQuery).mockReturnValue({ + vi.mocked(useNotifyDeckConfigurationQuery).mockReturnValue({ data: [{}], } as UseQueryResult) }) @@ -314,7 +317,7 @@ describe('useMissingProtocolHardware', () => { }) }) it('should return 1 conflicted slot', () => { - vi.mocked(useDeckConfigurationQuery).mockReturnValue(({ + vi.mocked(useNotifyDeckConfigurationQuery).mockReturnValue(({ data: [ { cutoutId: 'cutoutD3', @@ -343,14 +346,6 @@ describe('useMissingProtocolHardware', () => { connected: false, hasSlotConflict: true, }, - { - hardwareType: 'fixture', - cutoutFixtureId: 'singleRightSlot', - location: { - cutout: 'cutoutD3', - }, - hasSlotConflict: true, - }, ], conflictedSlots: ['D3'], }) @@ -374,6 +369,21 @@ describe('useMissingProtocolHardware', () => { data: { data: [mockHeaterShaker] }, isLoading: false, } as any) + vi.mocked(useNotifyDeckConfigurationQuery).mockReturnValue({ + data: [ + omitBy( + FLEX_SIMPLEST_DECK_CONFIG, + ({ cutoutId }) => cutoutId === 'cutoutD3' + ), + { + cutoutId: 'cutoutD3', + cutoutFixtureId: 'heaterShakerModuleV1', + opentronsModuleSerialNumber: mockHeaterShaker.serialNumber, + }, + ], + isLoading: false, + } as any) + const { result } = renderHook( () => useMissingProtocolHardware(PROTOCOL_ANALYSIS.id), { wrapper } @@ -384,7 +394,7 @@ describe('useMissingProtocolHardware', () => { conflictedSlots: [], }) }) - it('should return conflicting slot when module location is configured with something other than single slot fixture', () => { + it('should return conflicting slot when module location is configured with something other than module fixture', () => { vi.mocked(useInstrumentsQuery).mockReturnValue({ data: { data: [ @@ -404,7 +414,7 @@ describe('useMissingProtocolHardware', () => { isLoading: false, } as any) - vi.mocked(useDeckConfigurationQuery).mockReturnValue({ + vi.mocked(useNotifyDeckConfigurationQuery).mockReturnValue({ data: [ omitBy( FLEX_SIMPLEST_DECK_CONFIG, @@ -425,11 +435,10 @@ describe('useMissingProtocolHardware', () => { expect(result.current).toEqual({ missingProtocolHardware: [ { - hardwareType: 'fixture', - cutoutFixtureId: 'singleRightSlot', - location: { - cutout: 'cutoutD3', - }, + hardwareType: 'module', + moduleModel: 'heaterShakerModuleV1', + slot: 'D3', + connected: false, hasSlotConflict: true, }, ], diff --git a/app/src/pages/Protocols/hooks/index.ts b/app/src/pages/Protocols/hooks/index.ts index 964103dc5c5..93eadffba56 100644 --- a/app/src/pages/Protocols/hooks/index.ts +++ b/app/src/pages/Protocols/hooks/index.ts @@ -1,6 +1,5 @@ import last from 'lodash/last' import { - useDeckConfigurationQuery, useInstrumentsQuery, useModulesQuery, useProtocolAnalysisAsDocumentQuery, @@ -9,14 +8,19 @@ import { import { FLEX_ROBOT_TYPE, FLEX_SINGLE_SLOT_ADDRESSABLE_AREAS, - SINGLE_SLOT_FIXTURES, getCutoutIdForSlotName, getDeckDefFromRobotType, - RunTimeParameter, + getCutoutFixtureIdsForModuleModel, + getCutoutFixturesForModuleModel, + FLEX_MODULE_ADDRESSABLE_AREAS, + getModuleType, + MAGNETIC_MODULE_TYPE, + FLEX_USB_MODULE_ADDRESSABLE_AREAS, } from '@opentrons/shared-data' import { getLabwareSetupItemGroups } from '../utils' import { getProtocolUsesGripper } from '../../../organisms/ProtocolSetupInstruments/utils' import { useDeckConfigurationCompatibility } from '../../../resources/deck_configuration/hooks' +import { useNotifyDeckConfigurationQuery } from '../../../resources/deck_configuration' import type { CompletedProtocolAnalysis, @@ -26,11 +30,11 @@ import type { PipetteName, ProtocolAnalysisOutput, RobotType, + RunTimeParameter, } from '@opentrons/shared-data' import type { LabwareSetupItem } from '../utils' -import type { AttachedModule } from '@opentrons/api-client' -interface ProtocolPipette { +export interface ProtocolPipette { hardwareType: 'pipette' pipetteName: PipetteName mount: 'left' | 'right' @@ -82,9 +86,10 @@ export const useRequiredProtocolHardwareFromAnalysis = ( const robotType = FLEX_ROBOT_TYPE const deckDef = getDeckDefFromRobotType(robotType) - const { data: deckConfig = [] } = useDeckConfigurationQuery({ - refetchInterval: DECK_CONFIG_REFETCH_INTERVAL, - }) + const deckConfig = + useNotifyDeckConfigurationQuery({ + refetchInterval: DECK_CONFIG_REFETCH_INTERVAL, + })?.data ?? [] const deckConfigCompatibility = useDeckConfigurationCompatibility( robotType, analysis @@ -105,33 +110,42 @@ export const useRequiredProtocolHardwareFromAnalysis = ( ] : [] - const handleModuleConnectionCheckFor = ( - attachedModules: AttachedModule[], - model: ModuleModel - ): boolean => { - const ASSUME_ALWAYS_CONNECTED_MODULES = ['magneticBlockV1'] - - return !ASSUME_ALWAYS_CONNECTED_MODULES.includes(model) - ? attachedModules.some(m => m.moduleModel === model) - : true - } + const requiredModules: ProtocolModule[] = analysis.modules + .filter(m => getModuleType(m.model) !== MAGNETIC_MODULE_TYPE) + .map(({ location, model }) => { + const cutoutIdForSlotName = getCutoutIdForSlotName( + location.slotName, + deckDef + ) + const moduleFixtures = getCutoutFixturesForModuleModel(model, deckDef) - const requiredModules: ProtocolModule[] = analysis.modules.map( - ({ location, model }) => { + const configuredModuleSerialNumber = + deckConfig.find( + ({ cutoutId, cutoutFixtureId }) => + cutoutId === cutoutIdForSlotName && + moduleFixtures.map(mf => mf.id).includes(cutoutFixtureId) + )?.opentronsModuleSerialNumber ?? null + const isConnected = moduleFixtures.every( + mf => mf.expectOpentronsModuleSerialNumber + ) + ? attachedModules.some( + m => + m.moduleModel === model && + m.serialNumber === configuredModuleSerialNumber + ) + : true return { hardwareType: 'module', moduleModel: model, slot: location.slotName, - connected: handleModuleConnectionCheckFor(attachedModules, model), + connected: isConnected, hasSlotConflict: deckConfig.some( ({ cutoutId, cutoutFixtureId }) => cutoutId === getCutoutIdForSlotName(location.slotName, deckDef) && - cutoutFixtureId != null && - !SINGLE_SLOT_FIXTURES.includes(cutoutFixtureId) + cutoutFixtureId !== getCutoutFixtureIdsForModuleModel(model)[0] ), } - } - ) + }) const requiredPipettes: ProtocolPipette[] = analysis.pipettes.map( ({ mount, pipetteName }) => ({ @@ -161,16 +175,23 @@ export const useRequiredProtocolHardwareFromAnalysis = ( } ) - const requiredFixtures = requiredDeckConfigCompatibility.map( - ({ cutoutFixtureId, cutoutId, compatibleCutoutFixtureIds }) => ({ + const requiredFixtures = requiredDeckConfigCompatibility + // filter out all fixtures that only provide usb module addressable areas + // as they're handled in the requiredModules section via hardwareType === 'module' + .filter( + ({ requiredAddressableAreas }) => + !requiredAddressableAreas.every(modAA => + FLEX_USB_MODULE_ADDRESSABLE_AREAS.includes(modAA) + ) + ) + .map(({ cutoutFixtureId, cutoutId, compatibleCutoutFixtureIds }) => ({ hardwareType: 'fixture' as const, cutoutFixtureId: compatibleCutoutFixtureIds[0], location: { cutout: cutoutId }, hasSlotConflict: cutoutFixtureId != null && !compatibleCutoutFixtureIds.includes(cutoutFixtureId), - }) - ) + })) return { requiredProtocolHardware: [ @@ -269,7 +290,6 @@ const useMissingProtocolHardwareFromRequiredProtocolHardware = ( robotType, protocolAnalysis ) - // determine missing or conflicted hardware return { missingProtocolHardware: [ @@ -278,9 +298,16 @@ const useMissingProtocolHardwareFromRequiredProtocolHardware = ( ), ...deckConfigCompatibility .filter( - ({ cutoutFixtureId, compatibleCutoutFixtureIds }) => + ({ + cutoutFixtureId, + compatibleCutoutFixtureIds, + requiredAddressableAreas, + }) => cutoutFixtureId != null && - !compatibleCutoutFixtureIds.some(id => id === cutoutFixtureId) + !compatibleCutoutFixtureIds.some(id => id === cutoutFixtureId) && + !FLEX_MODULE_ADDRESSABLE_AREAS.some(modAA => + requiredAddressableAreas.includes(modAA) + ) // modules are already included via requiredProtocolHardware ) .map(({ compatibleCutoutFixtureIds, cutoutId }) => ({ hardwareType: 'fixture' as const, diff --git a/app/src/pages/RobotDashboard/AnalyticsOptInModal.tsx b/app/src/pages/RobotDashboard/AnalyticsOptInModal.tsx index e7772654a38..4073a356aee 100644 --- a/app/src/pages/RobotDashboard/AnalyticsOptInModal.tsx +++ b/app/src/pages/RobotDashboard/AnalyticsOptInModal.tsx @@ -28,7 +28,7 @@ interface AnalyticsOptInModalProps { export function AnalyticsOptInModal({ setShowAnalyticsOptInModal, }: AnalyticsOptInModalProps): JSX.Element { - const { t } = useTranslation(['app_settings', 'shared']) + const { t } = useTranslation(['app_settings', 'shared', 'branded']) const dispatch = useDispatch() const localRobot = useSelector(getLocalRobot) @@ -57,7 +57,7 @@ export function AnalyticsOptInModal({ } return ( - + () const localRobot = useSelector(getLocalRobot) const robotName = localRobot?.name != null ? localRobot.name : 'no name' @@ -144,7 +148,7 @@ export function RobotSettingsList(props: RobotSettingsListProps): JSX.Element { setCurrentOption('Privacy')} iconName="privacy" /> diff --git a/app/src/pages/RunSummary/index.tsx b/app/src/pages/RunSummary/index.tsx index e76a73ce1b9..e0f678ec424 100644 --- a/app/src/pages/RunSummary/index.tsx +++ b/app/src/pages/RunSummary/index.tsx @@ -54,9 +54,8 @@ import { EMPTY_TIMESTAMP } from '../../organisms/Devices/constants' import { RunTimer } from '../../organisms/Devices/ProtocolRun/RunTimer' import { useTrackEvent, - // ANALYTICS_PROTOCOL_RUN_CANCEL, - ANALYTICS_PROTOCOL_RUN_AGAIN, - ANALYTICS_PROTOCOL_RUN_FINISH, + ANALYTICS_PROTOCOL_RUN_ACTION, + ANALYTICS_PROTOCOL_PROCEED_TO_RUN, } from '../../redux/analytics' import { getLocalRobot } from '../../redux/discovery' import { RunFailedModal } from '../../organisms/OnDeviceDisplay/RunningProtocol' @@ -124,6 +123,10 @@ export function RunSummary(): JSX.Element { const [showRunAgainSpinner, setShowRunAgainSpinner] = React.useState( false ) + const robotSerialNumber = + localRobot?.health?.robot_serial ?? + localRobot?.serverHealth?.serialNumber ?? + null let headerText = t('run_complete_splash') if (runStatus === RUN_STATUS_FAILED) { @@ -167,10 +170,10 @@ export function RunSummary(): JSX.Element { setShowRunAgainSpinner(true) reset() trackEvent({ - name: 'proceedToRun', - properties: { sourceLocation: 'RunSummary' }, + name: ANALYTICS_PROTOCOL_PROCEED_TO_RUN, + properties: { sourceLocation: 'RunSummary', robotSerialNumber }, }) - trackProtocolRunEvent({ name: ANALYTICS_PROTOCOL_RUN_AGAIN }) + trackProtocolRunEvent({ name: ANALYTICS_PROTOCOL_RUN_ACTION.AGAIN }) } } } @@ -181,7 +184,7 @@ export function RunSummary(): JSX.Element { const handleClickSplash = (): void => { trackProtocolRunEvent({ - name: ANALYTICS_PROTOCOL_RUN_FINISH, + name: ANALYTICS_PROTOCOL_RUN_ACTION.FINISH, properties: robotAnalyticsData ?? undefined, }) setShowSplash(false) diff --git a/app/src/pages/RunningProtocol/__tests__/RunningProtocol.test.tsx b/app/src/pages/RunningProtocol/__tests__/RunningProtocol.test.tsx index 32f87a8047c..acf08a15d77 100644 --- a/app/src/pages/RunningProtocol/__tests__/RunningProtocol.test.tsx +++ b/app/src/pages/RunningProtocol/__tests__/RunningProtocol.test.tsx @@ -7,6 +7,7 @@ import { RUN_STATUS_BLOCKED_BY_OPEN_DOOR, RUN_STATUS_IDLE, RUN_STATUS_STOP_REQUESTED, + RUN_STATUS_AWAITING_RECOVERY, } from '@opentrons/api-client' import { useAllCommandsQuery, @@ -30,15 +31,17 @@ import { getLocalRobot } from '../../../redux/discovery' import { CancelingRunModal } from '../../../organisms/OnDeviceDisplay/RunningProtocol/CancelingRunModal' import { useTrackProtocolRunEvent } from '../../../organisms/Devices/hooks' import { useMostRecentCompletedAnalysis } from '../../../organisms/LabwarePositionCheck/useMostRecentCompletedAnalysis' +import { RunPausedSplash } from '../../../organisms/OnDeviceDisplay/RunningProtocol/RunPausedSplash' import { OpenDoorAlertModal } from '../../../organisms/OpenDoorAlertModal' import { RunningProtocol } from '..' import { - useNotifyLastRunCommandKey, + useNotifyLastRunCommand, useNotifyRunQuery, } from '../../../resources/runs' +import { useFeatureFlag } from '../../../redux/config' import type { UseQueryResult } from 'react-query' -import type { ProtocolAnalyses } from '@opentrons/api-client' +import type { ProtocolAnalyses, RunCommandSummary } from '@opentrons/api-client' vi.mock('@opentrons/react-api-client') vi.mock('../../../organisms/Devices/hooks') @@ -47,12 +50,15 @@ vi.mock('../../../organisms/RunTimeControl/hooks') vi.mock( '../../../organisms/LabwarePositionCheck/useMostRecentCompletedAnalysis' ) +vi.mock('../../../organisms/OnDeviceDisplay/RunningProtocol/RunPausedSplash') vi.mock('../../../organisms/RunTimeControl/hooks') vi.mock('../../../organisms/OnDeviceDisplay/RunningProtocol') vi.mock('../../../redux/discovery') vi.mock('../../../organisms/OnDeviceDisplay/RunningProtocol/CancelingRunModal') vi.mock('../../../organisms/OpenDoorAlertModal') vi.mock('../../../resources/runs') +vi.mock('../../../redux/config') + const RUN_ID = 'run_id' const ROBOT_NAME = 'otie' const PROTOCOL_ID = 'protocol_id' @@ -85,6 +91,7 @@ describe('RunningProtocol', () => { data: { id: RUN_ID, protocolId: PROTOCOL_ID, + errors: [], }, }, } as any) @@ -130,9 +137,12 @@ describe('RunningProtocol', () => { when(vi.mocked(useAllCommandsQuery)) .calledWith(RUN_ID, { cursor: null, pageLength: 1 }) .thenReturn(mockUseAllCommandsResponseNonDeterministic) - vi.mocked(useNotifyLastRunCommandKey).mockReturnValue({ - data: {}, - } as any) + vi.mocked(useNotifyLastRunCommand).mockReturnValue({ + key: 'FAKE_COMMAND_KEY', + } as RunCommandSummary) + when(vi.mocked(useFeatureFlag)) + .calledWith('enableRunNotes') + .thenReturn(true) }) afterEach(() => { @@ -166,6 +176,14 @@ describe('RunningProtocol', () => { expect(vi.mocked(OpenDoorAlertModal)).toHaveBeenCalled() }) + it(`should display a Run Paused splash screen if the run status is "${RUN_STATUS_AWAITING_RECOVERY}"`, () => { + when(vi.mocked(useRunStatus)) + .calledWith(RUN_ID, { refetchInterval: 5000 }) + .thenReturn(RUN_STATUS_AWAITING_RECOVERY) + render(`/runs/${RUN_ID}/run`) + expect(vi.mocked(RunPausedSplash)).toHaveBeenCalled() + }) + // ToDo (kj:04/04/2023) need to figure out the way to simulate swipe it.todo('should render RunningProtocolCommandList when swiping left') // const [{ getByText }] = render(`/runs/${RUN_ID}/run`) diff --git a/app/src/pages/RunningProtocol/index.tsx b/app/src/pages/RunningProtocol/index.tsx index 2fc56806679..0bd793acc8f 100644 --- a/app/src/pages/RunningProtocol/index.tsx +++ b/app/src/pages/RunningProtocol/index.tsx @@ -18,19 +18,20 @@ import { useSwipe, } from '@opentrons/components' import { - useAllCommandsQuery, useProtocolQuery, useRunActionMutations, } from '@opentrons/react-api-client' import { RUN_STATUS_STOP_REQUESTED, RUN_STATUS_BLOCKED_BY_OPEN_DOOR, + RUN_STATUS_AWAITING_RECOVERY, } from '@opentrons/api-client' +import { useFeatureFlag } from '../../redux/config' import { StepMeter } from '../../atoms/StepMeter' import { useMostRecentCompletedAnalysis } from '../../organisms/LabwarePositionCheck/useMostRecentCompletedAnalysis' import { - useNotifyLastRunCommandKey, + useNotifyLastRunCommand, useNotifyRunQuery, } from '../../resources/runs' import { InterventionModal } from '../../organisms/InterventionModal' @@ -51,8 +52,10 @@ import { } from '../../organisms/Devices/hooks' import { CancelingRunModal } from '../../organisms/OnDeviceDisplay/RunningProtocol/CancelingRunModal' import { ConfirmCancelRunModal } from '../../organisms/OnDeviceDisplay/RunningProtocol/ConfirmCancelRunModal' +import { RunPausedSplash } from '../../organisms/OnDeviceDisplay/RunningProtocol/RunPausedSplash' import { getLocalRobot } from '../../redux/discovery' import { OpenDoorAlertModal } from '../../organisms/OpenDoorAlertModal' +import { ErrorRecoveryFlows } from '../../organisms/ErrorRecoveryFlows' import type { OnDeviceRouteParams } from '../../App/types' @@ -92,16 +95,19 @@ export function RunningProtocol(): JSX.Element { const lastAnimatedCommand = React.useRef(null) const swipe = useSwipe() const robotSideAnalysis = useMostRecentCompletedAnalysis(runId) - const currentRunCommandKey = useNotifyLastRunCommandKey(runId, { + const lastRunCommand = useNotifyLastRunCommand(runId, { refetchInterval: LIVE_RUN_COMMANDS_POLL_MS, }) + const totalIndex = robotSideAnalysis?.commands.length const currentRunCommandIndex = robotSideAnalysis?.commands.findIndex( - c => c.key === currentRunCommandKey + c => c.key === lastRunCommand?.key ) const runStatus = useRunStatus(runId, { refetchInterval: RUN_STATUS_REFETCH_INTERVAL, }) + const [enableSplash, setEnableSplash] = React.useState(true) + const [showErrorRecovery, setShowErrorRecovery] = React.useState(false) const { startedAt, stoppedAt, completedAt } = useRunTimestamps(runId) const { data: runRecord } = useNotifyRunQuery(runId, { staleTime: Infinity }) const protocolId = runRecord?.data.protocolId ?? null @@ -117,6 +123,10 @@ export function RunningProtocol(): JSX.Element { const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId, robotName) const robotAnalyticsData = useRobotAnalyticsData(robotName) const robotType = useRobotType(robotName) + const errorType = runRecord?.data.errors[0]?.errorType + + const enableRunNotes = useFeatureFlag('enableRunNotes') + React.useEffect(() => { if ( currentOption === 'CurrentRunningProtocolCommand' && @@ -135,12 +145,6 @@ export function RunningProtocol(): JSX.Element { } }, [currentOption, swipe, swipe.setSwipeType]) - const { data: allCommandsQueryData } = useAllCommandsQuery(runId, { - cursor: null, - pageLength: 1, - }) - const lastRunCommand = allCommandsQueryData?.data[0] ?? null - React.useEffect(() => { if ( lastRunCommand != null && @@ -158,116 +162,148 @@ export function RunningProtocol(): JSX.Element { } }, [lastRunCommand, interventionModalCommandKey]) + const handleCompleteRecovery = (): void => { + setShowErrorRecovery(false) + setEnableSplash(false) + } + return ( <> - {runStatus === RUN_STATUS_BLOCKED_BY_OPEN_DOOR ? ( - + {showErrorRecovery ? ( + ) : null} - {runStatus === RUN_STATUS_STOP_REQUESTED ? : null} - - {robotSideAnalysis != null ? ( - - ) : null} - {showConfirmCancelRunModal ? ( - - ) : null} - {interventionModalCommandKey != null && - runRecord?.data != null && - lastRunCommand != null && - isInterventionCommand(lastRunCommand) ? ( - - ) : null} - - {robotSideAnalysis != null ? ( - currentOption === 'CurrentRunningProtocolCommand' ? ( - - (lastAnimatedCommand.current = newCommandKey) + {enableSplash && + runStatus === RUN_STATUS_AWAITING_RECOVERY && + enableRunNotes ? ( + setShowErrorRecovery(true)} + errorType={errorType} + protocolName={protocolName} + /> + ) : ( + <> + {runStatus === RUN_STATUS_BLOCKED_BY_OPEN_DOOR ? ( + + ) : null} + {runStatus === RUN_STATUS_STOP_REQUESTED ? ( + + ) : null} + + {robotSideAnalysis != null ? ( + - ) : ( - <> - + ) : null} + {interventionModalCommandKey != null && + runRecord?.data != null && + lastRunCommand != null && + isInterventionCommand(lastRunCommand) ? ( + + ) : null} + + {robotSideAnalysis != null ? ( + currentOption === 'CurrentRunningProtocolCommand' ? ( + + (lastAnimatedCommand.current = newCommandKey) + } + /> + ) : ( + <> + + + + ) + ) : ( + + )} + + - - - ) - ) : ( - - )} - - - + + - - + + )} ) } diff --git a/app/src/pages/Welcome/index.tsx b/app/src/pages/Welcome/index.tsx index 47bb9cbcb50..f5c1ac686bd 100644 --- a/app/src/pages/Welcome/index.tsx +++ b/app/src/pages/Welcome/index.tsx @@ -17,7 +17,7 @@ import screenImage from '../../assets/images/on-device-display/welcome_backgroun const IMAGE_ALT = 'Welcome screen background image' export function Welcome(): JSX.Element { - const { t } = useTranslation(['device_settings', 'shared']) + const { t } = useTranslation(['device_settings', 'shared', 'branded']) const history = useHistory() return ( @@ -30,7 +30,7 @@ export function Welcome(): JSX.Element { {IMAGE_ALT} - {t('welcome_title')} + {t('branded:welcome_title')} diff --git a/app/src/redux/analytics/constants.ts b/app/src/redux/analytics/constants.ts index 4eb663f0146..9cb3af568ac 100644 --- a/app/src/redux/analytics/constants.ts +++ b/app/src/redux/analytics/constants.ts @@ -1,19 +1,14 @@ +// ToDo (kk:04/25/2024) re-organized all constants + export const ANALYTICS_PIPETTE_OFFSET_STARTED: 'analytics:PIPETTE_OFFSET_STARTED' = 'analytics:PIPETTE_OFFSET_STARTED' export const ANALYTICS_TIP_LENGTH_STARTED: 'analytics:TIP_LENGTH_STARTED' = 'analytics:TIP_LENGTH_STARTED' -export const ANALYTICS_PROTOCOL_PROCEED_TO_RUN = 'proceedToRun' export const ANALYTICS_LIQUID_SETUP_VIEW_TOGGLE = 'liquidSetupViewToggle' export const ANALYTICS_ADD_CUSTOM_LABWARE = 'addCustomLabware' export const ANALYTICS_U2E_DRIVE_ALERT_DISMISSED = 'u2eDriverAlertDismissed' export const ANALYTICS_U2E_DRIVE_LINK_CLICKED = 'u2eDriverLinkClicked' -export const ANALYTICS_PROTOCOL_RUN_AGAIN = 'runAgain' -export const ANALYTICS_PROTOCOL_RUN_FINISH = 'runFinish' -export const ANALYTICS_PROTOCOL_RUN_PAUSE = 'runPause' -export const ANALYTICS_PROTOCOL_RUN_START = 'runStart' -export const ANALYTICS_PROTOCOL_RUN_RESUME = 'runResume' -export const ANALYTICS_PROTOCOL_RUN_CANCEL = 'runCancel' export const ANALYTICS_PROCEED_TO_MODULE_SETUP_STEP = 'proceed_to_module_setup_step' export const ANALYTICS_PROCEED_TO_LABWARE_SETUP_STEP = @@ -41,7 +36,27 @@ export const ANALYTICS_APP_UPDATE_NOTIFICATIONS_TOGGLED = export const ANALYTICS_OPEN_LABWARE_CREATOR_FROM_BOTTOM_OF_LABWARE_LIBRARY_LIST = 'openLabwareCreatorFromBottomOfLabwareLibraryList' export const ANALYTICS_SENT_TO_FLEX = 'sendToFlex' // This would be changed + export const ANALYTICS_ODD_APP_ERROR = 'oddError' +export const ANALYTICS_DESKTOP_APP_ERROR = 'desktopAppError' export const ANALYTICS_NOTIFICATION_PORT_BLOCK_ERROR = 'notificationPortBlockError' -export const ANALYTICS_DESKTOP_APP_ERROR = 'desktopAppError' + +export const ANALYTICS_PROTOCOL_RUN_ACTION = { + AGAIN: 'runAgain', + FINISH: 'runFinish', + PAUSE: 'runPause', + START: 'runStart', + RESUME: 'runResume', + CANCEL: 'runCancel', +} as const +export const ANALYTICS_PROTOCOL_PROCEED_TO_RUN = 'proceedToRun' + +export const ANALYTICS_STATE_ROBOT_UPDATE = { + IGNORE: 'robotUpdateIgnore', + INITIATE: 'robotUpdateInitiate', + ERROR: 'robotUpdateError', + COMPLETE: 'robotUpdateComplete', +} as const +export const ANALYTICS_ROBOT_UPDATE_VIEW = 'robotUpdateView' +export const ANALYTICS_ROBOT_UPDATE_CHANGE_LOG_VIEW = 'robotUpdateChangeLogView' diff --git a/app/src/redux/analytics/make-event.ts b/app/src/redux/analytics/make-event.ts index 8fdede1dbf2..da3a812fbdc 100644 --- a/app/src/redux/analytics/make-event.ts +++ b/app/src/redux/analytics/make-event.ts @@ -28,7 +28,7 @@ export function makeEvent( case RobotUpdate.ROBOTUPDATE_SET_UPDATE_SEEN: { const data = getBuildrootAnalyticsData(state, action.meta.robotName) return Promise.resolve({ - name: 'robotUpdateView', + name: Constants.ANALYTICS_ROBOT_UPDATE_VIEW, properties: { ...data }, }) } @@ -36,7 +36,7 @@ export function makeEvent( case RobotUpdate.ROBOTUPDATE_CHANGELOG_SEEN: { const data = getBuildrootAnalyticsData(state, action.meta.robotName) return Promise.resolve({ - name: 'robotUpdateChangeLogView', + name: Constants.ANALYTICS_ROBOT_UPDATE_CHANGE_LOG_VIEW, properties: { ...data }, }) } @@ -44,7 +44,7 @@ export function makeEvent( case RobotUpdate.ROBOTUPDATE_UPDATE_IGNORED: { const data = getBuildrootAnalyticsData(state, action.meta.robotName) return Promise.resolve({ - name: 'robotUpdateIgnore', + name: Constants.ANALYTICS_STATE_ROBOT_UPDATE.IGNORE, properties: { ...data }, }) } @@ -52,7 +52,7 @@ export function makeEvent( case RobotUpdate.ROBOTUPDATE_START_UPDATE: { const data = getBuildrootAnalyticsData(state) return Promise.resolve({ - name: 'robotUpdateInitiate', + name: Constants.ANALYTICS_STATE_ROBOT_UPDATE.INITIATE, properties: { ...data }, }) } @@ -60,7 +60,7 @@ export function makeEvent( case RobotUpdate.ROBOTUPDATE_UNEXPECTED_ERROR: { const data = getBuildrootAnalyticsData(state) return Promise.resolve({ - name: 'robotUpdateError', + name: Constants.ANALYTICS_STATE_ROBOT_UPDATE.ERROR, properties: { ...data }, }) } @@ -69,7 +69,7 @@ export function makeEvent( if (action.payload !== 'finished') return Promise.resolve(null) const data = getBuildrootAnalyticsData(state) return Promise.resolve({ - name: 'robotUpdateComplete', + name: Constants.ANALYTICS_STATE_ROBOT_UPDATE.COMPLETE, properties: { ...data }, }) } diff --git a/app/src/redux/analytics/selectors.ts b/app/src/redux/analytics/selectors.ts index fcb9ab18a2d..9667954ff72 100644 --- a/app/src/redux/analytics/selectors.ts +++ b/app/src/redux/analytics/selectors.ts @@ -32,7 +32,10 @@ export function getBuildrootAnalyticsData( ? getRobotUpdateRobot(state) : getViewableRobots(state).find(r => r.name === robotName) ?? null - if (updateVersion === null || robot === null) return null + if (robot === null) return null + + const robotSerialNumber = + robot?.health?.robot_serial ?? robot?.serverHealth?.serialNumber ?? null const currentVersion = getRobotApiVersion(robot) ?? 'unknown' const currentSystem = getRobotSystemType(robot) ?? 'unknown' @@ -40,8 +43,9 @@ export function getBuildrootAnalyticsData( return { currentVersion, currentSystem, - updateVersion, + updateVersion: updateVersion ?? 'unknown', error: session != null && 'error' in session ? session.error : null, + robotSerialNumber, } } diff --git a/app/src/redux/analytics/types.ts b/app/src/redux/analytics/types.ts index 0b85ce91718..197660f7794 100644 --- a/app/src/redux/analytics/types.ts +++ b/app/src/redux/analytics/types.ts @@ -41,6 +41,7 @@ export interface BuildrootAnalyticsData { currentSystem: string updateVersion: string error: string | null + robotSerialNumber: string | null } export interface PipetteOffsetCalibrationAnalyticsData { diff --git a/app/src/redux/config/selectors.ts b/app/src/redux/config/selectors.ts index 4d32befab43..3e630973e51 100644 --- a/app/src/redux/config/selectors.ts +++ b/app/src/redux/config/selectors.ts @@ -78,7 +78,7 @@ export const getUpdateChannelOptions = (state: State): SelectOption[] => { export const getIsOnDevice: (state: State) => boolean = createSelector( getConfig, - config => config?.isOnDevice ?? false + config => !!(config?.isOnDevice ?? false) ) export const getProtocolsDesktopSortKey: ( diff --git a/app/src/redux/discovery/__fixtures__/index.ts b/app/src/redux/discovery/__fixtures__/index.ts index 329e18504dd..ea7a4e0f195 100644 --- a/app/src/redux/discovery/__fixtures__/index.ts +++ b/app/src/redux/discovery/__fixtures__/index.ts @@ -18,6 +18,7 @@ export const mockHealthResponse = { api_version: '0.0.0-mock', fw_version: '0.0.0-mock', system_version: '0.0.0-mock', + robot_serial: 'mock-serial', logs: [] as string[], protocol_api_version: [2, 0] as [number, number], } diff --git a/app/src/redux/protocol-storage/__fixtures__/index.ts b/app/src/redux/protocol-storage/__fixtures__/index.ts index 56f7f4d021a..be5500203a2 100644 --- a/app/src/redux/protocol-storage/__fixtures__/index.ts +++ b/app/src/redux/protocol-storage/__fixtures__/index.ts @@ -11,6 +11,17 @@ export const storedProtocolData: StoredProtocolData = { modified: 123456789, } +export const storedProtocolDataWithoutRunTimeParameters: StoredProtocolData = { + protocolKey: 'protocolKeyStub', + mostRecentAnalysis: ({ + ...simpleAnalysisFileFixture, + runTimeParameters: [], + } as any) as ProtocolAnalysisOutput, + srcFileNames: ['fakeSrcFileName'], + srcFiles: ['fakeSrcFile' as any], + modified: 123456789, +} + export const storedProtocolDir: StoredProtocolDir = { dirPath: 'path/to/protocol/dir', modified: 1234556789, diff --git a/app/src/redux/robot-settings/types.ts b/app/src/redux/robot-settings/types.ts index 5571be6a441..3f998311c46 100644 --- a/app/src/redux/robot-settings/types.ts +++ b/app/src/redux/robot-settings/types.ts @@ -1,20 +1,10 @@ +import type { + RobotSettings, + RobotSettingsField, + RobotSettingsResponse, +} from '@opentrons/api-client' import type { RobotApiRequestMeta } from '../robot-api/types' -export interface RobotSettingsField { - id: string - title: string - description: string - value: boolean | null - restart_required?: boolean -} - -export type RobotSettings = RobotSettingsField[] - -export interface RobotSettingsResponse { - settings: RobotSettings - links?: { restart?: string } -} - export interface PerRobotRobotSettingsState { settings: RobotSettings restartPath: string | null @@ -94,3 +84,6 @@ export type RobotSettingsAction = | UpdateSettingAction | UpdateSettingSuccessAction | UpdateSettingFailureAction + +// TODO(bh, 2024-03-26): update type imports elsewhere to @opentrons/api-client +export type { RobotSettings, RobotSettingsField, RobotSettingsResponse } diff --git a/app/src/redux/shell/index.ts b/app/src/redux/shell/index.ts index a709a770d7f..5a918f75eb3 100644 --- a/app/src/redux/shell/index.ts +++ b/app/src/redux/shell/index.ts @@ -5,4 +5,4 @@ export * from './update' export * from './is-ready/actions' export * from './is-ready/selectors' -export const CURRENT_VERSION: string = (global as any)._PKG_VERSION_ +export const CURRENT_VERSION: string = _PKG_VERSION_ diff --git a/app/src/redux/shell/remote.ts b/app/src/redux/shell/remote.ts index 18508789ada..5717e5bdeaf 100644 --- a/app/src/redux/shell/remote.ts +++ b/app/src/redux/shell/remote.ts @@ -1,7 +1,11 @@ // access main process remote modules via attachments to `global` -import type { AxiosRequestConfig } from 'axios' -import type { ResponsePromise } from '@opentrons/api-client' -import type { Remote, NotifyTopic, NotifyResponseData } from './types' +import type { AxiosRequestConfig, AxiosResponse } from 'axios' +import type { + Remote, + NotifyTopic, + NotifyResponseData, + IPCSafeFormData, +} from './types' const emptyRemote: Remote = {} as any @@ -20,18 +24,40 @@ export const remote: Remote = new Proxy(emptyRemote, { }, }) -export function appShellRequestor( +// FormData and File objects can't be sent through invoke(). +// This converts them into simpler objects that can be. +// app-shell will convert them back. +async function proxyFormData(formData: FormData): Promise { + const result: IPCSafeFormData = [] + for (const [name, value] of formData.entries()) { + if (value instanceof File) { + result.push({ + type: 'file', + name, + // todo(mm, 2024-04-24): Send just the (full) filename instead of the file + // contents, to avoid the IPC message ballooning into several MB. + value: await value.arrayBuffer(), + filename: value.name, + }) + } else { + result.push({ type: 'string', name, value }) + } + } + + return result +} + +export async function appShellRequestor( config: AxiosRequestConfig -): ResponsePromise { +): Promise> { const { data } = config - // special case: protocol files and form data cannot be sent through invoke. proxy by protocolKey and handle in app-shell const formDataProxy = data instanceof FormData - ? { formDataProxy: { protocolKey: data.get('key') } } + ? { proxiedFormData: await proxyFormData(data) } : data const configProxy = { ...config, data: formDataProxy } - return remote.ipcRenderer.invoke('usb:request', configProxy) + return await remote.ipcRenderer.invoke('usb:request', configProxy) } interface CallbackStore { diff --git a/app/src/redux/shell/types.ts b/app/src/redux/shell/types.ts index d83cee94b15..8f485e24bd7 100644 --- a/app/src/redux/shell/types.ts +++ b/app/src/redux/shell/types.ts @@ -141,6 +141,8 @@ export type NotifyTopic = | 'robot-server/runs/current_command' | 'robot-server/runs' | `robot-server/runs/${string}` + | 'robot-server/deck_configuration' + | `robot-server/runs/pre_serialized_commands/${string}` export interface NotifySubscribeAction { type: 'shell:NOTIFY_SUBSCRIBE' @@ -164,3 +166,18 @@ export type ShellAction = | RobotMassStorageDeviceEnumerated | RobotMassStorageDeviceRemoved | NotifySubscribeAction + +export type IPCSafeFormDataEntry = + | { + type: 'string' + name: string + value: string + } + | { + type: 'file' + name: string + value: ArrayBuffer + filename: string + } + +export type IPCSafeFormData = IPCSafeFormDataEntry[] diff --git a/app/src/resources/__tests__/useNotifyService.test.ts b/app/src/resources/__tests__/useNotifyService.test.ts index fdb531ab1cd..b11db79ee43 100644 --- a/app/src/resources/__tests__/useNotifyService.test.ts +++ b/app/src/resources/__tests__/useNotifyService.test.ts @@ -8,19 +8,18 @@ import { useNotifyService } from '../useNotifyService' import { appShellListener } from '../../redux/shell/remote' import { useTrackEvent } from '../../redux/analytics' import { notifySubscribeAction } from '../../redux/shell' -import { useIsFlex } from '../../organisms/Devices/hooks/useIsFlex' import type { Mock } from 'vitest' import type { HostConfig } from '@opentrons/api-client' import type { QueryOptionsWithPolling } from '../useNotifyService' +vi.unmock('../useNotifyService') vi.mock('react-redux') vi.mock('@opentrons/react-api-client') vi.mock('../../redux/analytics') vi.mock('../../redux/shell/remote', () => ({ appShellListener: vi.fn(), })) -vi.mock('../../organisms/Devices/hooks/useIsFlex') const MOCK_HOST_CONFIG: HostConfig = { hostname: 'MOCK_HOST' } const MOCK_TOPIC = '/test/topic' as any @@ -35,12 +34,10 @@ describe('useNotifyService', () => { beforeEach(() => { mockDispatch = vi.fn() - mockHTTPRefetch = vi.fn() mockTrackEvent = vi.fn() vi.mocked(useTrackEvent).mockReturnValue(mockTrackEvent) vi.mocked(useDispatch).mockReturnValue(mockDispatch) vi.mocked(useHost).mockReturnValue(MOCK_HOST_CONFIG) - vi.mocked(useIsFlex).mockReturnValue(true) vi.mocked(appShellListener).mockClear() }) @@ -50,14 +47,13 @@ describe('useNotifyService', () => { }) it('should trigger an HTTP refetch and subscribe action on a successful initial mount', () => { - renderHook(() => + const { result } = renderHook(() => useNotifyService({ topic: MOCK_TOPIC, - setRefetch: mockHTTPRefetch, options: MOCK_OPTIONS, } as any) ) - expect(mockHTTPRefetch).toHaveBeenCalledWith('once') + expect(result.current.isNotifyEnabled).toEqual(true) expect(mockDispatch).toHaveBeenCalledWith( notifySubscribeAction(MOCK_HOST_CONFIG.hostname, MOCK_TOPIC) ) @@ -65,40 +61,37 @@ describe('useNotifyService', () => { }) it('should not subscribe to notifications if forceHttpPolling is true', () => { - renderHook(() => + const { result } = renderHook(() => useNotifyService({ topic: MOCK_TOPIC, - setRefetch: mockHTTPRefetch, options: { ...MOCK_OPTIONS, forceHttpPolling: true }, } as any) ) - expect(mockHTTPRefetch).toHaveBeenCalled() + expect(result.current.isNotifyEnabled).toEqual(true) expect(appShellListener).not.toHaveBeenCalled() expect(mockDispatch).not.toHaveBeenCalled() }) it('should not subscribe to notifications if enabled is false', () => { - renderHook(() => + const { result } = renderHook(() => useNotifyService({ topic: MOCK_TOPIC, - setRefetch: mockHTTPRefetch, options: { ...MOCK_OPTIONS, enabled: false }, } as any) ) - expect(mockHTTPRefetch).toHaveBeenCalled() + expect(result.current.isNotifyEnabled).toEqual(true) expect(appShellListener).not.toHaveBeenCalled() expect(mockDispatch).not.toHaveBeenCalled() }) it('should not subscribe to notifications if staleTime is Infinity', () => { - renderHook(() => + const { result } = renderHook(() => useNotifyService({ topic: MOCK_TOPIC, - setRefetch: mockHTTPRefetch, options: { ...MOCK_OPTIONS, staleTime: Infinity }, } as any) ) - expect(mockHTTPRefetch).toHaveBeenCalled() + expect(result.current.isNotifyEnabled).toEqual(true) expect(appShellListener).not.toHaveBeenCalled() expect(mockDispatch).not.toHaveBeenCalled() }) @@ -108,14 +101,15 @@ describe('useNotifyService', () => { const errorSpy = vi.spyOn(console, 'error') errorSpy.mockImplementation(() => {}) - renderHook(() => + const { result } = renderHook(() => useNotifyService({ topic: MOCK_TOPIC, setRefetch: mockHTTPRefetch, options: MOCK_OPTIONS, } as any) ) - expect(mockHTTPRefetch).toHaveBeenCalledWith('always') + + expect(result.current.isNotifyEnabled).toEqual(true) }) it('should return set HTTP refetch to always and fire an analytics reporting event if the connection was refused', () => { @@ -125,7 +119,7 @@ describe('useNotifyService', () => { // eslint-disable-next-line n/no-callback-literal callback('ECONNREFUSED') }) - const { rerender } = renderHook(() => + const { rerender, result } = renderHook(() => useNotifyService({ topic: MOCK_TOPIC, setRefetch: mockHTTPRefetch, @@ -134,7 +128,7 @@ describe('useNotifyService', () => { ) expect(mockTrackEvent).toHaveBeenCalled() rerender() - expect(mockHTTPRefetch).toHaveBeenCalledWith('always') + expect(result.current.isNotifyEnabled).toEqual(true) }) it('should trigger a single HTTP refetch if the refetch flag was returned', () => { @@ -144,7 +138,7 @@ describe('useNotifyService', () => { // eslint-disable-next-line n/no-callback-literal callback({ refetch: true }) }) - const { rerender } = renderHook(() => + const { rerender, result } = renderHook(() => useNotifyService({ topic: MOCK_TOPIC, setRefetch: mockHTTPRefetch, @@ -152,7 +146,7 @@ describe('useNotifyService', () => { } as any) ) rerender() - expect(mockHTTPRefetch).toHaveBeenCalledWith('once') + expect(result.current.isNotifyEnabled).toEqual(true) }) it('should trigger a single HTTP refetch if the unsubscribe flag was returned', () => { @@ -162,22 +156,20 @@ describe('useNotifyService', () => { // eslint-disable-next-line n/no-callback-literal callback({ unsubscribe: true }) }) - const { rerender } = renderHook(() => + const { rerender, result } = renderHook(() => useNotifyService({ topic: MOCK_TOPIC, - setRefetch: mockHTTPRefetch, options: MOCK_OPTIONS, } as any) ) rerender() - expect(mockHTTPRefetch).toHaveBeenCalledWith('once') + expect(result.current.isNotifyEnabled).toEqual(true) }) it('should clean up the listener on dismount', () => { const { unmount } = renderHook(() => useNotifyService({ topic: MOCK_TOPIC, - setRefetch: mockHTTPRefetch, options: MOCK_OPTIONS, }) ) @@ -190,7 +182,6 @@ describe('useNotifyService', () => { useNotifyService({ hostOverride: MOCK_HOST_CONFIG, topic: MOCK_TOPIC, - setRefetch: mockHTTPRefetch, options: MOCK_OPTIONS, }) ) diff --git a/app/src/resources/deck_configuration/__tests__/hooks.test.ts b/app/src/resources/deck_configuration/__tests__/hooks.test.ts index 29e12c44bb1..fc71c602780 100644 --- a/app/src/resources/deck_configuration/__tests__/hooks.test.ts +++ b/app/src/resources/deck_configuration/__tests__/hooks.test.ts @@ -1,7 +1,6 @@ import { describe, it, vi, beforeEach } from 'vitest' import { when } from 'vitest-when' -import { useDeckConfigurationQuery } from '@opentrons/react-api-client' import { SINGLE_LEFT_SLOT_FIXTURE, SINGLE_RIGHT_SLOT_FIXTURE, @@ -10,10 +9,12 @@ import { WASTE_CHUTE_RIGHT_ADAPTER_COVERED_FIXTURE, } from '@opentrons/shared-data' +import { useNotifyDeckConfigurationQuery } from '../useNotifyDeckConfigurationQuery' + import type { UseQueryResult } from 'react-query' import type { DeckConfiguration } from '@opentrons/shared-data' -vi.mock('@opentrons/react-api-client') +vi.mock('../useNotifyDeckConfigurationQuery') const MOCK_DECK_CONFIG: DeckConfiguration = [ { @@ -52,7 +53,7 @@ const MOCK_DECK_CONFIG: DeckConfiguration = [ describe('useDeckConfigurationCompatibility', () => { beforeEach(() => { - when(useDeckConfigurationQuery) + when(useNotifyDeckConfigurationQuery) .calledWith() .thenReturn({ data: MOCK_DECK_CONFIG, diff --git a/app/src/resources/deck_configuration/hooks.ts b/app/src/resources/deck_configuration/hooks.ts index 95b92e9f7dc..ed48b705c5c 100644 --- a/app/src/resources/deck_configuration/hooks.ts +++ b/app/src/resources/deck_configuration/hooks.ts @@ -1,5 +1,4 @@ import { getInitialAndMovedLabwareInSlots } from '@opentrons/components' -import { useDeckConfigurationQuery } from '@opentrons/react-api-client' import { FLEX_ROBOT_TYPE, getAddressableAreasInProtocol, @@ -7,13 +6,9 @@ import { getCutoutIdForAddressableArea, getDeckDefFromRobotType, getLabwareDisplayName, - SINGLE_LEFT_SLOT_FIXTURE, SINGLE_SLOT_FIXTURES, - THERMOCYCLER_MODULE_TYPE, } from '@opentrons/shared-data' -import { getProtocolModulesInfo } from '../../organisms/Devices/ProtocolRun/utils/getProtocolModulesInfo' - import type { CompletedProtocolAnalysis, CutoutConfigProtocolSpec, @@ -22,6 +17,8 @@ import type { RobotType, } from '@opentrons/shared-data' +import { useNotifyDeckConfigurationQuery } from './useNotifyDeckConfigurationQuery' + const DECK_CONFIG_REFETCH_INTERVAL = 5000 export interface CutoutConfigAndCompatibility extends CutoutConfigProtocolSpec { @@ -34,8 +31,9 @@ export function useDeckConfigurationCompatibility( protocolAnalysis: CompletedProtocolAnalysis | ProtocolAnalysisOutput | null ): CutoutConfigAndCompatibility[] { const deckConfig = - useDeckConfigurationQuery({ refetchInterval: DECK_CONFIG_REFETCH_INTERVAL }) - .data ?? [] + useNotifyDeckConfigurationQuery({ + refetchInterval: DECK_CONFIG_REFETCH_INTERVAL, + }).data ?? [] if (robotType !== FLEX_ROBOT_TYPE) return [] const deckDef = getDeckDefFromRobotType(robotType) const allAddressableAreas = @@ -47,17 +45,6 @@ export function useDeckConfigurationCompatibility( ? getInitialAndMovedLabwareInSlots(protocolAnalysis) : [] - const protocolModulesInfo = - protocolAnalysis != null - ? getProtocolModulesInfo(protocolAnalysis, deckDef) - : [] - - const hasThermocycler = - protocolModulesInfo.find( - protocolMod => - protocolMod.moduleDef.moduleType === THERMOCYCLER_MODULE_TYPE - ) != null - return deckConfig.reduce( (acc, { cutoutId, cutoutFixtureId }) => { const fixturesThatMountToCutoutId = getCutoutFixturesForCutoutId( @@ -69,7 +56,6 @@ export function useDeckConfigurationCompatibility( getCutoutIdForAddressableArea(aa, fixturesThatMountToCutoutId) === cutoutId ) - const compatibleCutoutFixtureIds = fixturesThatMountToCutoutId .filter(cf => requiredAddressableAreasForCutoutId.every(aa => @@ -106,11 +92,7 @@ export function useDeckConfigurationCompatibility( cutoutId, cutoutFixtureId, requiredAddressableAreas: requiredAddressableAreasForCutoutId, - // Thermocycler requires an "empty" (single slot) fixture in A1 that is not referenced directly in protocol - compatibleCutoutFixtureIds: - hasThermocycler && cutoutId === 'cutoutA1' - ? [SINGLE_LEFT_SLOT_FIXTURE] - : compatibleCutoutFixtureIds, + compatibleCutoutFixtureIds, missingLabwareDisplayName, }, ] diff --git a/app/src/resources/deck_configuration/index.ts b/app/src/resources/deck_configuration/index.ts new file mode 100644 index 00000000000..da47ee2de54 --- /dev/null +++ b/app/src/resources/deck_configuration/index.ts @@ -0,0 +1,4 @@ +export * from './hooks' +export * from './types' +export * from './utils' +export * from './useNotifyDeckConfigurationQuery' diff --git a/app/src/resources/deck_configuration/useNotifyDeckConfigurationQuery.ts b/app/src/resources/deck_configuration/useNotifyDeckConfigurationQuery.ts new file mode 100644 index 00000000000..827350bd47e --- /dev/null +++ b/app/src/resources/deck_configuration/useNotifyDeckConfigurationQuery.ts @@ -0,0 +1,24 @@ +import { useDeckConfigurationQuery } from '@opentrons/react-api-client' + +import { useNotifyService } from '../useNotifyService' + +import type { UseQueryResult } from 'react-query' +import type { DeckConfiguration } from '@opentrons/shared-data' +import type { QueryOptionsWithPolling } from '../useNotifyService' + +export function useNotifyDeckConfigurationQuery( + options: QueryOptionsWithPolling = {} +): UseQueryResult { + const { notifyOnSettled, isNotifyEnabled } = useNotifyService({ + topic: 'robot-server/deck_configuration', + options, + }) + + const httpQueryResult = useDeckConfigurationQuery({ + ...options, + enabled: options?.enabled !== false && isNotifyEnabled, + onSettled: notifyOnSettled, + }) + + return httpQueryResult +} diff --git a/app/src/resources/deck_configuration/utils.ts b/app/src/resources/deck_configuration/utils.ts index 9efaeea3a57..5306b967d4b 100644 --- a/app/src/resources/deck_configuration/utils.ts +++ b/app/src/resources/deck_configuration/utils.ts @@ -25,8 +25,9 @@ export function getIsFixtureMismatch( deckConfigProtocolSpec: CutoutConfigAndCompatibility[] ): boolean { const isFixtureMismatch = !deckConfigProtocolSpec.every( - ({ cutoutFixtureId, compatibleCutoutFixtureIds }) => - isMatchedFixture(cutoutFixtureId, compatibleCutoutFixtureIds) + ({ cutoutFixtureId, compatibleCutoutFixtureIds }) => { + return isMatchedFixture(cutoutFixtureId, compatibleCutoutFixtureIds) + } ) return isFixtureMismatch } diff --git a/app/src/resources/instruments/hooks.ts b/app/src/resources/instruments/hooks.ts new file mode 100644 index 00000000000..31a40f5fdd0 --- /dev/null +++ b/app/src/resources/instruments/hooks.ts @@ -0,0 +1,62 @@ +import { + getGripperDisplayName, + getPipetteModelSpecs, + getPipetteNameSpecs, + GRIPPER_MODELS, +} from '@opentrons/shared-data' +import { useIsOEMMode } from '../robot-settings/hooks' + +import type { + GripperModel, + PipetteModel, + PipetteModelSpecs, + PipetteName, + PipetteNameSpecs, +} from '@opentrons/shared-data' + +export function usePipetteNameSpecs( + name: PipetteName +): PipetteNameSpecs | null { + const isOEMMode = useIsOEMMode() + const pipetteNameSpecs = getPipetteNameSpecs(name) + + if (pipetteNameSpecs == null) return null + + const brandedDisplayName = pipetteNameSpecs.displayName + const anonymizedDisplayName = pipetteNameSpecs.displayName.replace( + 'Flex ', + '' + ) + + const displayName = isOEMMode ? anonymizedDisplayName : brandedDisplayName + + return { ...pipetteNameSpecs, displayName } +} + +export function usePipetteModelSpecs( + model: PipetteModel +): PipetteModelSpecs | null { + const modelSpecificFields = getPipetteModelSpecs(model) + const pipetteNameSpecs = usePipetteNameSpecs( + modelSpecificFields?.name as PipetteName + ) + + if (modelSpecificFields == null || pipetteNameSpecs == null) return null + + return { ...modelSpecificFields, displayName: pipetteNameSpecs.displayName } +} + +export function useGripperDisplayName(gripperModel: GripperModel): string { + const isOEMMode = useIsOEMMode() + + let brandedDisplayName = '' + + // check to only call display name helper for a gripper model + if (GRIPPER_MODELS.includes(gripperModel)) { + brandedDisplayName = getGripperDisplayName(gripperModel) + } + + const anonymizedDisplayName = brandedDisplayName.replace('Flex ', '') + + return isOEMMode ? anonymizedDisplayName : brandedDisplayName +} diff --git a/app/src/resources/maintenance_runs/useNotifyCurrentMaintenanceRun.ts b/app/src/resources/maintenance_runs/useNotifyCurrentMaintenanceRun.ts index 28859afe393..1f9bbf2ff3b 100644 --- a/app/src/resources/maintenance_runs/useNotifyCurrentMaintenanceRun.ts +++ b/app/src/resources/maintenance_runs/useNotifyCurrentMaintenanceRun.ts @@ -1,31 +1,23 @@ -import * as React from 'react' - import { useCurrentMaintenanceRun } from '@opentrons/react-api-client' import { useNotifyService } from '../useNotifyService' import type { UseQueryResult } from 'react-query' import type { MaintenanceRun } from '@opentrons/api-client' -import type { - QueryOptionsWithPolling, - HTTPRefetchFrequency, -} from '../useNotifyService' +import type { QueryOptionsWithPolling } from '../useNotifyService' export function useNotifyCurrentMaintenanceRun( options: QueryOptionsWithPolling = {} ): UseQueryResult | UseQueryResult { - const [refetch, setRefetch] = React.useState(null) - - useNotifyService({ + const { notifyOnSettled, isNotifyEnabled } = useNotifyService({ topic: 'robot-server/maintenance_runs/current_run', - setRefetch, options, }) const httpQueryResult = useCurrentMaintenanceRun({ ...options, - enabled: options?.enabled !== false && refetch != null, - onSettled: refetch === 'once' ? () => setRefetch(null) : () => null, + enabled: options?.enabled !== false && isNotifyEnabled, + onSettled: notifyOnSettled, }) return httpQueryResult diff --git a/app/src/resources/robot-settings/hooks.ts b/app/src/resources/robot-settings/hooks.ts new file mode 100644 index 00000000000..a548b154b56 --- /dev/null +++ b/app/src/resources/robot-settings/hooks.ts @@ -0,0 +1,22 @@ +import { useSelector } from 'react-redux' +import { useRobotSettingsQuery } from '@opentrons/react-api-client' +import { getIsOnDevice } from '../../redux/config' + +import type { RobotSettingsField } from '@opentrons/api-client' + +/** + * a hook to tell the ODD that the robot is in OEM mode + * limit to ODD, since some instrument name hooks will be common to both ODD and desktop + * @returns boolean + */ +export function useIsOEMMode(): boolean { + const { settings } = useRobotSettingsQuery().data ?? {} + const isOnDevice = useSelector(getIsOnDevice) + + const oemModeSetting = + (settings ?? []).find( + (setting: RobotSettingsField) => setting?.id === 'enableOEMMode' + )?.value ?? false + + return oemModeSetting && isOnDevice +} diff --git a/app/src/resources/runs/index.ts b/app/src/resources/runs/index.ts index be5fabb4970..91595d17f08 100644 --- a/app/src/resources/runs/index.ts +++ b/app/src/resources/runs/index.ts @@ -2,4 +2,5 @@ export * from './hooks' export * from './utils' export * from './useNotifyAllRunsQuery' export * from './useNotifyRunQuery' -export * from './useNotifyLastRunCommandKey' +export * from './useNotifyLastRunCommand' +export * from './useNotifyAllCommandsAsPreSerializedList' diff --git a/app/src/resources/runs/useNotifyAllCommandsAsPreSerializedList.ts b/app/src/resources/runs/useNotifyAllCommandsAsPreSerializedList.ts new file mode 100644 index 00000000000..67922a9e3ec --- /dev/null +++ b/app/src/resources/runs/useNotifyAllCommandsAsPreSerializedList.ts @@ -0,0 +1,27 @@ +import { useAllCommandsAsPreSerializedList } from '@opentrons/react-api-client' + +import { useNotifyService } from '../useNotifyService' + +import type { UseQueryResult } from 'react-query' +import type { AxiosError } from 'axios' +import type { CommandsData, GetCommandsParams } from '@opentrons/api-client' +import type { QueryOptionsWithPolling } from '../useNotifyService' + +export function useNotifyAllCommandsAsPreSerializedList( + runId: string | null, + params?: GetCommandsParams | null, + options: QueryOptionsWithPolling = {} +): UseQueryResult { + const { notifyOnSettled, isNotifyEnabled } = useNotifyService({ + topic: `robot-server/runs/pre_serialized_commands/${runId}`, + options, + }) + + const httpResponse = useAllCommandsAsPreSerializedList(runId, params, { + ...options, + enabled: options?.enabled !== false && isNotifyEnabled, + onSettled: notifyOnSettled, + }) + + return httpResponse +} diff --git a/app/src/resources/runs/useNotifyAllRunsQuery.ts b/app/src/resources/runs/useNotifyAllRunsQuery.ts index 1ae93ffc713..ab340039cfd 100644 --- a/app/src/resources/runs/useNotifyAllRunsQuery.ts +++ b/app/src/resources/runs/useNotifyAllRunsQuery.ts @@ -1,5 +1,3 @@ -import * as React from 'react' - import { useAllRunsQuery } from '@opentrons/react-api-client' import { useNotifyService } from '../useNotifyService' @@ -8,21 +6,15 @@ import type { UseQueryResult } from 'react-query' import type { AxiosError } from 'axios' import type { HostConfig, GetRunsParams, Runs } from '@opentrons/api-client' import type { UseAllRunsQueryOptions } from '@opentrons/react-api-client/src/runs/useAllRunsQuery' -import type { - QueryOptionsWithPolling, - HTTPRefetchFrequency, -} from '../useNotifyService' +import type { QueryOptionsWithPolling } from '../useNotifyService' export function useNotifyAllRunsQuery( params: GetRunsParams = {}, options: QueryOptionsWithPolling = {}, hostOverride?: HostConfig | null ): UseQueryResult { - const [refetch, setRefetch] = React.useState(null) - - useNotifyService({ + const { notifyOnSettled, isNotifyEnabled } = useNotifyService({ topic: 'robot-server/runs', - setRefetch, options, hostOverride, }) @@ -31,8 +23,8 @@ export function useNotifyAllRunsQuery( params, { ...(options as UseAllRunsQueryOptions), - enabled: options?.enabled !== false && refetch != null, - onSettled: refetch === 'once' ? () => setRefetch(null) : () => null, + enabled: options?.enabled !== false && isNotifyEnabled, + onSettled: notifyOnSettled, }, hostOverride ) diff --git a/app/src/resources/runs/useNotifyLastRunCommand.ts b/app/src/resources/runs/useNotifyLastRunCommand.ts new file mode 100644 index 00000000000..b7c2289ffc8 --- /dev/null +++ b/app/src/resources/runs/useNotifyLastRunCommand.ts @@ -0,0 +1,23 @@ +import { useNotifyService } from '../useNotifyService' +import { useLastRunCommand } from '../../organisms/Devices/hooks/useLastRunCommand' + +import type { CommandsData, RunCommandSummary } from '@opentrons/api-client' +import type { QueryOptionsWithPolling } from '../useNotifyService' + +export function useNotifyLastRunCommand( + runId: string, + options: QueryOptionsWithPolling = {} +): RunCommandSummary | null { + const { notifyOnSettled, isNotifyEnabled } = useNotifyService({ + topic: 'robot-server/runs/current_command', + options, + }) + + const httpResponse = useLastRunCommand(runId, { + ...options, + enabled: options?.enabled !== false && isNotifyEnabled, + onSettled: notifyOnSettled, + }) + + return httpResponse +} diff --git a/app/src/resources/runs/useNotifyLastRunCommandKey.ts b/app/src/resources/runs/useNotifyLastRunCommandKey.ts deleted file mode 100644 index 9c908a70749..00000000000 --- a/app/src/resources/runs/useNotifyLastRunCommandKey.ts +++ /dev/null @@ -1,31 +0,0 @@ -import * as React from 'react' - -import { useNotifyService } from '../useNotifyService' -import { useLastRunCommandKey } from '../../organisms/Devices/hooks/useLastRunCommandKey' - -import type { CommandsData } from '@opentrons/api-client' -import type { - QueryOptionsWithPolling, - HTTPRefetchFrequency, -} from '../useNotifyService' - -export function useNotifyLastRunCommandKey( - runId: string, - options: QueryOptionsWithPolling = {} -): string | null { - const [refetch, setRefetch] = React.useState(null) - - useNotifyService({ - topic: 'robot-server/runs/current_command', - setRefetch, - options, - }) - - const httpResponse = useLastRunCommandKey(runId, { - ...options, - enabled: options?.enabled !== false && refetch != null, - onSettled: refetch === 'once' ? () => setRefetch(null) : () => null, - }) - - return httpResponse -} diff --git a/app/src/resources/runs/useNotifyRunQuery.ts b/app/src/resources/runs/useNotifyRunQuery.ts index 2ca72687341..ae6b1b1bdcc 100644 --- a/app/src/resources/runs/useNotifyRunQuery.ts +++ b/app/src/resources/runs/useNotifyRunQuery.ts @@ -1,35 +1,27 @@ -import * as React from 'react' - import { useRunQuery } from '@opentrons/react-api-client' import { useNotifyService } from '../useNotifyService' import type { UseQueryResult } from 'react-query' import type { Run } from '@opentrons/api-client' -import type { - QueryOptionsWithPolling, - HTTPRefetchFrequency, -} from '../useNotifyService' +import type { QueryOptionsWithPolling } from '../useNotifyService' import type { NotifyTopic } from '../../redux/shell/types' export function useNotifyRunQuery( runId: string | null, options: QueryOptionsWithPolling = {} ): UseQueryResult { - const [refetch, setRefetch] = React.useState(null) - const isEnabled = options.enabled !== false && runId != null - useNotifyService({ + const { notifyOnSettled, isNotifyEnabled } = useNotifyService({ topic: `robot-server/runs/${runId}` as NotifyTopic, - setRefetch, options: { ...options, enabled: options.enabled != null && runId != null }, }) const httpResponse = useRunQuery(runId, { ...options, - enabled: isEnabled && refetch != null, - onSettled: refetch === 'once' ? () => setRefetch(null) : () => null, + enabled: isEnabled && isNotifyEnabled, + onSettled: notifyOnSettled, }) return httpResponse diff --git a/app/src/resources/useNotifyService.ts b/app/src/resources/useNotifyService.ts index 19831dc9c62..1cf1d1dc3fa 100644 --- a/app/src/resources/useNotifyService.ts +++ b/app/src/resources/useNotifyService.ts @@ -10,7 +10,6 @@ import { useTrackEvent, ANALYTICS_NOTIFICATION_PORT_BLOCK_ERROR, } from '../redux/analytics' -import { useIsFlex } from '../organisms/Devices/hooks/useIsFlex' import type { UseQueryOptions } from 'react-query' import type { HostConfig } from '@opentrons/api-client' @@ -25,24 +24,28 @@ export interface QueryOptionsWithPolling interface UseNotifyServiceProps { topic: NotifyTopic - setRefetch: (refetch: HTTPRefetchFrequency) => void options: QueryOptionsWithPolling hostOverride?: HostConfig | null } +interface UseNotifyServiceResults { + notifyOnSettled: () => void + isNotifyEnabled: boolean +} + export function useNotifyService({ topic, - setRefetch, options, hostOverride, -}: UseNotifyServiceProps): void { +}: UseNotifyServiceProps): UseNotifyServiceResults { const dispatch = useDispatch() const hostFromProvider = useHost() const host = hostOverride ?? hostFromProvider const hostname = host?.hostname ?? null const doTrackEvent = useTrackEvent() - const isFlex = useIsFlex(host?.robotName ?? '') const seenHostname = React.useRef(null) + const [refetch, setRefetch] = React.useState(null) + const { enabled, staleTime, forceHttpPolling } = options const shouldUseNotifications = @@ -78,11 +81,10 @@ export function useNotifyService({ } }, [topic, hostname, shouldUseNotifications]) - function onDataEvent(data: NotifyResponseData): void { + const onDataEvent = React.useCallback((data: NotifyResponseData): void => { if (data === 'ECONNFAILED' || data === 'ECONNREFUSED') { setRefetch('always') - // TODO(jh 2023-02-23): remove the robot type check once OT-2s support MQTT. - if (data === 'ECONNREFUSED' && isFlex) { + if (data === 'ECONNREFUSED') { doTrackEvent({ name: ANALYTICS_NOTIFICATION_PORT_BLOCK_ERROR, properties: {}, @@ -91,5 +93,13 @@ export function useNotifyService({ } else if ('refetch' in data || 'unsubscribe' in data) { setRefetch('once') } - } + }, []) + + const notifyOnSettled = React.useCallback(() => { + if (refetch === 'once') { + setRefetch(null) + } + }, [refetch]) + + return { notifyOnSettled, isNotifyEnabled: refetch != null } } diff --git a/app/typings/global.d.ts b/app/typings/global.d.ts index 772bcf9ffd0..de736627240 100644 --- a/app/typings/global.d.ts +++ b/app/typings/global.d.ts @@ -1,6 +1,4 @@ declare const global: typeof globalThis & { - _PKG_VERSION_: string - _OPENTRONS_PROJECT_: string APP_SHELL_REMOTE: { // sa 02-02-2024 any typing this because importing the IpcRenderer type // from electron makes this ambient type declaration a module instead of @@ -9,3 +7,6 @@ declare const global: typeof globalThis & { [key: string]: any } } + +declare const _PKG_VERSION_: string +declare const _OPENTRONS_PROJECT_: string diff --git a/app/typings/remark.d.ts b/app/typings/remark.d.ts deleted file mode 100644 index 2eb55d6f77e..00000000000 --- a/app/typings/remark.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -declare module 'remark' { - const remark: any - // eslint-disable-next-line import/no-default-export - export default remark -} - -declare module 'remark-react' { - const reactRenderer: any - // eslint-disable-next-line import/no-default-export - export default reactRenderer -} diff --git a/app/vite.config.ts b/app/vite.config.ts index 9710acdd240..f88d492056a 100644 --- a/app/vite.config.ts +++ b/app/vite.config.ts @@ -6,57 +6,66 @@ import postCssApply from 'postcss-apply' import postColorModFunction from 'postcss-color-mod-function' import postCssPresetEnv from 'postcss-preset-env' import lostCss from 'lost' +import { versionForProject } from '../scripts/git-version.mjs' +import type { UserConfig } from 'vite' -export default defineConfig({ - // this makes imports relative rather than absolute - base: '', - build: { - // Relative to the root - outDir: 'dist', - }, - plugins: [ - react({ - include: '**/*.tsx', - babel: { - // Use babel.config.js files - configFile: true, +export default defineConfig( + async(): Promise => { + const project = process.env.OPENTRONS_PROJECT ?? 'robot-stack' + const version = await versionForProject(project) + return { + // this makes imports relative rather than absolute + base: '', + build: { + // Relative to the root + outDir: 'dist', }, - }), - ], - optimizeDeps: { - esbuildOptions: { - target: 'es2020', - }, - }, - css: { - postcss: { plugins: [ - postCssImport({ root: 'src/' }), - postCssApply(), - postColorModFunction(), - postCssPresetEnv({ stage: 0 }), - lostCss(), + react({ + include: '**/*.tsx', + babel: { + // Use babel.config.js files + configFile: true, + }, + }), ], - }, - }, - define: { - 'process.env': process.env, - global: 'globalThis', - }, - resolve: { - alias: { - '@opentrons/components/styles': path.resolve( - '../components/src/index.module.css' - ), - '@opentrons/components': path.resolve('../components/src/index.ts'), - '@opentrons/shared-data': path.resolve('../shared-data/js/index.ts'), - '@opentrons/step-generation': path.resolve( - '../step-generation/src/index.ts' - ), - '@opentrons/api-client': path.resolve('../api-client/src/index.ts'), - '@opentrons/react-api-client': path.resolve( - '../react-api-client/src/index.ts' - ), - }, - }, -}) + optimizeDeps: { + esbuildOptions: { + target: 'es2020', + }, + }, + css: { + postcss: { + plugins: [ + postCssImport({ root: 'src/' }), + postCssApply(), + postColorModFunction(), + postCssPresetEnv({ stage: 0 }), + lostCss(), + ], + }, + }, + define: { + 'process.env': process.env, + global: 'globalThis', + _PKG_VERSION_: JSON.stringify(version), + _OPENTRONS_PROJECT_: JSON.stringify(project), + }, + resolve: { + alias: { + '@opentrons/components/styles': path.resolve( + '../components/src/index.module.css' + ), + '@opentrons/components': path.resolve('../components/src/index.ts'), + '@opentrons/shared-data': path.resolve('../shared-data/js/index.ts'), + '@opentrons/step-generation': path.resolve( + '../step-generation/src/index.ts' + ), + '@opentrons/api-client': path.resolve('../api-client/src/index.ts'), + '@opentrons/react-api-client': path.resolve( + '../react-api-client/src/index.ts' + ), + }, + }, + } + }) diff --git a/components/Makefile b/components/Makefile index bcb90baf56b..c79c02a2f7c 100644 --- a/components/Makefile +++ b/components/Makefile @@ -5,7 +5,7 @@ port ?= 6060 # These variables can be overriden when make is invoked to customize the # behavior of jest -tests ?= +tests ?= src cov_opts ?= --coverage=true test_opts ?= diff --git a/components/src/atoms/CheckboxField/__tests__/CheckboxField.test.tsx b/components/src/atoms/CheckboxField/__tests__/CheckboxField.test.tsx index 58014d85f11..12778d0965f 100644 --- a/components/src/atoms/CheckboxField/__tests__/CheckboxField.test.tsx +++ b/components/src/atoms/CheckboxField/__tests__/CheckboxField.test.tsx @@ -41,7 +41,7 @@ describe('CheckboxField', () => { // INNER_STYLE_NO_VALUE expect(checkBoxIcon).toHaveStyle(`width: 1.25rem`) expect(checkBoxIcon).toHaveStyle(`min-width: 1.25rem`) - expect(checkBoxIcon).toHaveStyle(`color: ${String(COLORS.grey60)}`) + expect(checkBoxIcon).toHaveStyle(`color: ${String(COLORS.grey50)}`) expect(checkBoxIcon).toHaveStyle(`display: flex`) expect(checkBoxIcon).toHaveStyle( `border-radius: ${String(BORDERS.borderRadius2)}` @@ -82,7 +82,7 @@ describe('CheckboxField', () => { const checkBoxIcon = screen.getByTestId('CheckboxField_icon') expect(checkBoxIcon).toHaveStyle(`width: 1.25rem`) expect(checkBoxIcon).toHaveStyle(`min-width: 1.25rem`) - expect(checkBoxIcon).toHaveStyle(`color: ${String(COLORS.blue60)}`) + expect(checkBoxIcon).toHaveStyle(`color: ${String(COLORS.blue50)}`) expect(checkBoxIcon).toHaveStyle(`display: flex`) expect(checkBoxIcon).toHaveStyle( `border-radius: ${String(BORDERS.borderRadius2)}` @@ -99,7 +99,7 @@ describe('CheckboxField', () => { const checkBoxIcon = screen.getByTestId('CheckboxField_icon') expect(checkBoxIcon).toHaveStyle(`width: 1.25rem`) expect(checkBoxIcon).toHaveStyle(`min-width: 1.25rem`) - expect(checkBoxIcon).toHaveStyle(`color: ${String(COLORS.grey60)}`) + expect(checkBoxIcon).toHaveStyle(`color: ${String(COLORS.grey50)}`) expect(checkBoxIcon).toHaveStyle(`display: flex`) expect(checkBoxIcon).toHaveStyle( `border-radius: ${String(BORDERS.borderRadius2)}` diff --git a/components/src/atoms/StepMeter/index.tsx b/components/src/atoms/StepMeter/index.tsx index 14bbf48c6ca..91f151fb5c9 100644 --- a/components/src/atoms/StepMeter/index.tsx +++ b/components/src/atoms/StepMeter/index.tsx @@ -5,13 +5,15 @@ import { RESPONSIVENESS, SPACING } from '../../ui-style-constants' import { COLORS } from '../../helix-design-system' import { POSITION_ABSOLUTE, POSITION_RELATIVE } from '../../styles' -interface StepMeterProps { +import type { StyleProps } from '../../primitives' + +interface StepMeterProps extends StyleProps { totalSteps: number currentStep: number | null } export const StepMeter = (props: StepMeterProps): JSX.Element => { - const { totalSteps, currentStep } = props + const { totalSteps, currentStep, ...styleProps } = props const progress = currentStep != null ? currentStep : 0 const percentComplete = `${ // this logic puts a cap at 100% percentComplete which we should never run into @@ -21,7 +23,7 @@ export const StepMeter = (props: StepMeterProps): JSX.Element => { }%` const StepMeterContainer = css` - position: ${POSITION_RELATIVE}; + position: ${styleProps.position ? styleProps.position : POSITION_RELATIVE}; height: ${SPACING.spacing4}; background-color: ${COLORS.grey30}; @media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} { @@ -41,7 +43,11 @@ export const StepMeter = (props: StepMeterProps): JSX.Element => { ` return ( - + ) diff --git a/components/src/atoms/StyledText/StyledText.stories.tsx b/components/src/atoms/StyledText/StyledText.stories.tsx index 12f8ab8c16a..388f7e79bdf 100644 --- a/components/src/atoms/StyledText/StyledText.stories.tsx +++ b/components/src/atoms/StyledText/StyledText.stories.tsx @@ -1,87 +1,107 @@ +/* eslint-disable storybook/prefer-pascal-case */ import * as React from 'react' -import { StyledText } from './' -import { TYPOGRAPHY } from '../../ui-style-constants' -import type { Story, Meta } from '@storybook/react' +import { SPACING, TYPOGRAPHY } from '../../ui-style-constants' +import { Flex } from '../../primitives' +import { StyledText } from './index' +import type { Meta, StoryObj } from '@storybook/react' -export default { +const meta: Meta = { title: 'Library/Atoms/StyledText', component: StyledText, -} as Meta + decorators: [ + Story => ( + + + + ), + ], +} + +export default meta -const Template: Story> = args => ( - -) +type Story = StoryObj const dummyText = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Purus sapien nunc dolor, aliquet nibh placerat et nisl, arcu. Pellentesque blandit sollicitudin vitae morbi morbi vulputate cursus tellus. Amet proin donec proin id aliquet in nullam.' -export const h1 = Template.bind({}) -h1.args = { - as: 'h1', - children: dummyText, +export const h1: Story = { + args: { + as: 'h1', + children: dummyText, + }, } -export const h2 = Template.bind({}) -h2.args = { - as: 'h2', - children: dummyText, +export const h2: Story = { + args: { + as: 'h2', + children: dummyText, + }, } -export const h3 = Template.bind({}) -h3.args = { - as: 'h3', - children: dummyText, +export const h3: Story = { + args: { + as: 'h3', + children: dummyText, + }, } -export const h6 = Template.bind({}) -h6.args = { - as: 'h6', - children: dummyText, +export const h6: Story = { + args: { + as: 'h6', + children: dummyText, + }, } -export const p = Template.bind({}) -p.args = { - as: 'p', - children: dummyText, +export const p: Story = { + args: { + as: 'p', + children: dummyText, + }, } -export const label = Template.bind({}) -label.args = { - as: 'label', - children: dummyText, +export const label: Story = { + args: { + as: 'label', + children: dummyText, + }, } -export const h2SemiBold = Template.bind({}) -h2SemiBold.args = { - as: 'h2', - fontWeight: TYPOGRAPHY.fontWeightSemiBold, - children: dummyText, +export const h2SemiBold: Story = { + args: { + as: 'h2', + fontWeight: TYPOGRAPHY.fontWeightSemiBold, + children: dummyText, + }, } -export const h3SemiBold = Template.bind({}) -h3SemiBold.args = { - as: 'h3', - fontWeight: TYPOGRAPHY.fontWeightSemiBold, - children: dummyText, +export const h3SemiBold: Story = { + args: { + as: 'h3', + fontWeight: TYPOGRAPHY.fontWeightSemiBold, + children: dummyText, + }, } -export const h6SemiBold = Template.bind({}) -h6SemiBold.args = { - as: 'h6', - fontWeight: TYPOGRAPHY.fontWeightSemiBold, - children: dummyText, +export const h6SemiBold: Story = { + args: { + as: 'h6', + fontWeight: TYPOGRAPHY.fontWeightSemiBold, + children: dummyText, + }, } -export const pSemiBold = Template.bind({}) -pSemiBold.args = { - as: 'p', - fontWeight: TYPOGRAPHY.fontWeightSemiBold, - children: dummyText, +export const pSemiBold: Story = { + args: { + as: 'p', + fontWeight: TYPOGRAPHY.fontWeightSemiBold, + children: dummyText, + }, } -export const labelSemiBold = Template.bind({}) -labelSemiBold.args = { - as: 'label', - fontWeight: TYPOGRAPHY.fontWeightSemiBold, - children: dummyText, +export const labelSemiBold: Story = { + args: { + as: 'label', + fontWeight: TYPOGRAPHY.fontWeightSemiBold, + children: dummyText, + }, } diff --git a/components/src/atoms/buttons/__tests__/AlertPrimaryButton.test.tsx b/components/src/atoms/buttons/__tests__/AlertPrimaryButton.test.tsx index 3a56b84d0c9..41c1f3c0d28 100644 --- a/components/src/atoms/buttons/__tests__/AlertPrimaryButton.test.tsx +++ b/components/src/atoms/buttons/__tests__/AlertPrimaryButton.test.tsx @@ -24,7 +24,7 @@ describe('AlertPrimaryButton', () => { it('renders alert primary button with text', () => { render(props) const button = screen.getByText('alert primary button') - expect(button).toHaveStyle(`background-color: ${COLORS.red55}`) + expect(button).toHaveStyle(`background-color: ${COLORS.red50}`) expect(button).toHaveStyle( `padding: ${SPACING.spacing8} ${SPACING.spacing16} ${SPACING.spacing8} ${SPACING.spacing16}` ) diff --git a/components/src/atoms/buttons/__tests__/PrimaryButton.test.tsx b/components/src/atoms/buttons/__tests__/PrimaryButton.test.tsx index 4ec8c16357a..8353bba24f9 100644 --- a/components/src/atoms/buttons/__tests__/PrimaryButton.test.tsx +++ b/components/src/atoms/buttons/__tests__/PrimaryButton.test.tsx @@ -23,7 +23,7 @@ describe('PrimaryButton', () => { it('renders primary button with text', () => { render(props) const button = screen.getByText('primary button') - expect(button).toHaveStyle(`background-color: ${COLORS.blue60}`) + expect(button).toHaveStyle(`background-color: ${COLORS.blue50}`) expect(button).toHaveStyle( `padding: ${SPACING.spacing8} ${SPACING.spacing16} ${SPACING.spacing8} ${SPACING.spacing16}` ) @@ -51,14 +51,14 @@ describe('PrimaryButton', () => { render(props) const button = screen.getByText('primary button') fireEvent.mouseOver(button) - expect(button).toHaveStyle(`background-color: ${COLORS.blue60}`) + expect(button).toHaveStyle(`background-color: ${COLORS.blue50}`) }) it('renders primary button with text and different background color', () => { props.backgroundColor = COLORS.red50 render(props) const button = screen.getByText('primary button') - expect(button).toHaveStyle(`background-color: ${COLORS.blue60}`) + expect(button).toHaveStyle(`background-color: ${COLORS.red50}`) expect(button).toHaveStyle(`color: ${COLORS.white}`) }) }) diff --git a/components/src/atoms/buttons/__tests__/SecondaryButton.test.tsx b/components/src/atoms/buttons/__tests__/SecondaryButton.test.tsx index c2f1df7f388..c1c016e58f4 100644 --- a/components/src/atoms/buttons/__tests__/SecondaryButton.test.tsx +++ b/components/src/atoms/buttons/__tests__/SecondaryButton.test.tsx @@ -35,7 +35,7 @@ describe('SecondaryButton', () => { expect(button).toHaveStyle( `text-transform: ${TYPOGRAPHY.textTransformNone}` ) - expect(button).toHaveStyle(`color: ${COLORS.blue55}`) + expect(button).toHaveStyle(`color: ${COLORS.blue50}`) }) it('renders secondary button with text and disabled', () => { @@ -49,6 +49,6 @@ describe('SecondaryButton', () => { props.color = COLORS.red50 render(props) const button = screen.getByText('secondary button') - expect(button).toHaveStyle(`color: ${COLORS.blue55}`) + expect(button).toHaveStyle(`color: ${COLORS.red50}`) }) }) diff --git a/components/src/hardware-sim/BaseDeck/BaseDeck.tsx b/components/src/hardware-sim/BaseDeck/BaseDeck.tsx index e664cb10277..db72c865cd3 100644 --- a/components/src/hardware-sim/BaseDeck/BaseDeck.tsx +++ b/components/src/hardware-sim/BaseDeck/BaseDeck.tsx @@ -15,6 +15,8 @@ import { WASTE_CHUTE_ONLY_FIXTURES, WASTE_CHUTE_STAGING_AREA_FIXTURES, HEATERSHAKER_MODULE_V1, + MODULE_FIXTURES_BY_MODEL, + STAGING_AREA_SLOT_WITH_MAGNETIC_BLOCK_V1_FIXTURE, } from '@opentrons/shared-data' import { RobotCoordinateSpace } from '../RobotCoordinateSpace' @@ -32,6 +34,7 @@ import { WasteChuteFixture } from './WasteChuteFixture' import { WasteChuteStagingAreaFixture } from './WasteChuteStagingAreaFixture' import type { + CutoutFixtureId, DeckConfiguration, LabwareDefinition2, LabwareLocation, @@ -101,11 +104,20 @@ export function BaseDeck(props: BaseDeckProps): JSX.Element { const singleSlotFixtures = deckConfig.filter( fixture => fixture.cutoutFixtureId != null && - SINGLE_SLOT_FIXTURES.includes(fixture.cutoutFixtureId) + (SINGLE_SLOT_FIXTURES.includes(fixture.cutoutFixtureId) || + // If module fixture is loaded, still visualize singleSlotFixture underneath for consistency + Object.entries(MODULE_FIXTURES_BY_MODEL) + .reduce( + (acc, [_model, fixtures]) => [...acc, ...fixtures], + [] + ) + .includes(fixture.cutoutFixtureId)) ) const stagingAreaFixtures = deckConfig.filter( fixture => - fixture.cutoutFixtureId === STAGING_AREA_RIGHT_SLOT_FIXTURE && + (fixture.cutoutFixtureId === STAGING_AREA_RIGHT_SLOT_FIXTURE || + fixture.cutoutFixtureId === + STAGING_AREA_SLOT_WITH_MAGNETIC_BLOCK_V1_FIXTURE) && STAGING_AREA_CUTOUTS.includes(fixture.cutoutId) ) const trashBinFixtures = deckConfig.filter( diff --git a/components/src/hardware-sim/DeckConfigurator/DeckConfigurator.stories.tsx b/components/src/hardware-sim/DeckConfigurator/DeckConfigurator.stories.tsx index dc900541fd6..f29b2cffc02 100644 --- a/components/src/hardware-sim/DeckConfigurator/DeckConfigurator.stories.tsx +++ b/components/src/hardware-sim/DeckConfigurator/DeckConfigurator.stories.tsx @@ -71,6 +71,12 @@ const deckConfig: CutoutConfig[] = [ }, ] +const staticFixtures = [ + { location: 'cutoutB2', label: 'Tip rack' }, + { location: 'cutoutC2', label: 'Labware' }, + { location: 'cutoutD2', label: 'Labware' }, +] + export const Default = Template.bind({}) Default.args = { deckConfig, @@ -85,3 +91,12 @@ ReadOnly.args = { handleClickRemove: cutoutId => console.log(`remove at ${cutoutId}`), readOnly: true, } + +export const ReadOnlyWithStaticFixtures = Template.bind({}) +ReadOnlyWithStaticFixtures.args = { + deckConfig, + handleClickAdd: () => {}, + handleClickRemove: () => {}, + readOnly: true, + additionalStaticFixtures: staticFixtures, +} diff --git a/components/src/hardware-sim/DeckConfigurator/EmptyConfigFixture.tsx b/components/src/hardware-sim/DeckConfigurator/EmptyConfigFixture.tsx index fba7dfc57cf..d790f2e922d 100644 --- a/components/src/hardware-sim/DeckConfigurator/EmptyConfigFixture.tsx +++ b/components/src/hardware-sim/DeckConfigurator/EmptyConfigFixture.tsx @@ -8,10 +8,13 @@ import { RESPONSIVENESS } from '../../ui-style-constants' import { BORDERS, COLORS } from '../../helix-design-system' import { RobotCoordsForeignObject } from '../Deck/RobotCoordsForeignObject' import { + COLUMN_1_SINGLE_SLOT_FIXTURE_WIDTH, + COLUMN_2_SINGLE_SLOT_FIXTURE_WIDTH, + COLUMN_3_SINGLE_SLOT_FIXTURE_WIDTH, COLUMN_1_X_ADJUSTMENT, + COLUMN_2_X_ADJUSTMENT, COLUMN_3_X_ADJUSTMENT, FIXTURE_HEIGHT, - SINGLE_SLOT_FIXTURE_WIDTH, Y_ADJUSTMENT, } from './constants' @@ -39,22 +42,40 @@ export function EmptyConfigFixture( */ const [xSlotPosition = 0, ySlotPosition = 0] = standardSlotCutout?.position ?? [] - - const isColumnOne = - fixtureLocation === 'cutoutA1' || - fixtureLocation === 'cutoutB1' || - fixtureLocation === 'cutoutC1' || - fixtureLocation === 'cutoutD1' - const xAdjustment = isColumnOne - ? COLUMN_1_X_ADJUSTMENT - : COLUMN_3_X_ADJUSTMENT - const x = xSlotPosition + xAdjustment + let x = xSlotPosition + let width = 0 + switch (fixtureLocation) { + case 'cutoutA1': + case 'cutoutB1': + case 'cutoutC1': + case 'cutoutD1': { + x = xSlotPosition + COLUMN_1_X_ADJUSTMENT + width = COLUMN_1_SINGLE_SLOT_FIXTURE_WIDTH + break + } + case 'cutoutA2': + case 'cutoutB2': + case 'cutoutC2': + case 'cutoutD2': { + x = xSlotPosition + COLUMN_2_X_ADJUSTMENT + width = COLUMN_2_SINGLE_SLOT_FIXTURE_WIDTH + break + } + case 'cutoutA3': + case 'cutoutB3': + case 'cutoutC3': + case 'cutoutD3': { + x = xSlotPosition + COLUMN_3_X_ADJUSTMENT + width = COLUMN_3_SINGLE_SLOT_FIXTURE_WIDTH + break + } + } const y = ySlotPosition + Y_ADJUSTMENT return ( void + selected?: boolean +} + +const HEATER_SHAKER_MODULE_FIXTURE_DISPLAY_NAME = 'Heater-Shaker' + +export function HeaterShakerFixture( + props: HeaterShakerFixtureProps +): JSX.Element { + const { + deckDefinition, + handleClickRemove, + fixtureLocation, + cutoutFixtureId, + selected = false, + } = props + + const cutoutDef = deckDefinition.locations.cutouts.find( + cutout => cutout.id === fixtureLocation + ) + + /** + * deck definition cutout position is the position of the single slot located within that cutout + * so, to get the position of the cutout itself we must add an adjustment to the slot position + * the adjustment for x is different for right side/left side + */ + const [xSlotPosition = 0, ySlotPosition = 0] = cutoutDef?.position ?? [] + + const isColumnOne = + fixtureLocation === 'cutoutA1' || + fixtureLocation === 'cutoutB1' || + fixtureLocation === 'cutoutC1' || + fixtureLocation === 'cutoutD1' + const xAdjustment = isColumnOne + ? COLUMN_1_X_ADJUSTMENT + : COLUMN_3_X_ADJUSTMENT + const x = xSlotPosition + xAdjustment + + const y = ySlotPosition + Y_ADJUSTMENT + + const editableStyle = selected ? CONFIG_STYLE_SELECTED : CONFIG_STYLE_EDITABLE + return ( + + handleClickRemove(fixtureLocation, cutoutFixtureId) + : () => {} + } + > + + {HEATER_SHAKER_MODULE_FIXTURE_DISPLAY_NAME} + + {handleClickRemove != null ? ( + + ) : null} + + + ) +} diff --git a/components/src/hardware-sim/DeckConfigurator/MagneticBlockFixture.tsx b/components/src/hardware-sim/DeckConfigurator/MagneticBlockFixture.tsx new file mode 100644 index 00000000000..d266402d0dd --- /dev/null +++ b/components/src/hardware-sim/DeckConfigurator/MagneticBlockFixture.tsx @@ -0,0 +1,130 @@ +import * as React from 'react' + +import { Icon } from '../../icons' +import { Btn, Text } from '../../primitives' +import { TYPOGRAPHY } from '../../ui-style-constants' +import { COLORS } from '../../helix-design-system' +import { RobotCoordsForeignObject } from '../Deck/RobotCoordsForeignObject' +import { + COLUMN_1_SINGLE_SLOT_FIXTURE_WIDTH, + COLUMN_2_SINGLE_SLOT_FIXTURE_WIDTH, + COLUMN_3_SINGLE_SLOT_FIXTURE_WIDTH, + COLUMN_1_X_ADJUSTMENT, + COLUMN_2_X_ADJUSTMENT, + COLUMN_3_X_ADJUSTMENT, + FIXTURE_HEIGHT, + Y_ADJUSTMENT, + CONFIG_STYLE_EDITABLE, + CONFIG_STYLE_READ_ONLY, + STAGING_AREA_FIXTURE_WIDTH, + CONFIG_STYLE_SELECTED, +} from './constants' + +import type { + CutoutFixtureId, + CutoutId, + DeckDefinition, +} from '@opentrons/shared-data' + +interface MagneticBlockFixtureProps { + deckDefinition: DeckDefinition + fixtureLocation: CutoutId + cutoutFixtureId: CutoutFixtureId + handleClickRemove?: ( + fixtureLocation: CutoutId, + cutoutFixtureId: CutoutFixtureId + ) => void + hasStagingArea?: boolean + selected?: boolean +} + +const MAGNETIC_BLOCK_FIXTURE_DISPLAY_NAME = 'Mag Block' +const STAGING_AREA_WITH_MAGNETIC_BLOCK_DISPLAY_NAME = 'Mag + staging' + +export function MagneticBlockFixture( + props: MagneticBlockFixtureProps +): JSX.Element { + const { + deckDefinition, + fixtureLocation, + handleClickRemove, + cutoutFixtureId, + hasStagingArea, + selected = false, + } = props + + const standardSlotCutout = deckDefinition.locations.cutouts.find( + cutout => cutout.id === fixtureLocation + ) + + /** + * deck definition cutout position is the position of the single slot located within that cutout + * so, to get the position of the cutout itself we must add an adjustment to the slot position + * the adjustment for x is different for right side/left side + */ + const [xSlotPosition = 0, ySlotPosition = 0] = + standardSlotCutout?.position ?? [] + let x = xSlotPosition + let width = 0 + let displayName = hasStagingArea + ? STAGING_AREA_WITH_MAGNETIC_BLOCK_DISPLAY_NAME + : MAGNETIC_BLOCK_FIXTURE_DISPLAY_NAME + switch (fixtureLocation) { + case 'cutoutA1': + case 'cutoutB1': + case 'cutoutC1': + case 'cutoutD1': { + x = xSlotPosition + COLUMN_1_X_ADJUSTMENT + width = COLUMN_1_SINGLE_SLOT_FIXTURE_WIDTH + break + } + case 'cutoutA2': + case 'cutoutB2': + case 'cutoutC2': + case 'cutoutD2': { + x = xSlotPosition + COLUMN_2_X_ADJUSTMENT + width = COLUMN_2_SINGLE_SLOT_FIXTURE_WIDTH + displayName = 'Mag' + break + } + case 'cutoutA3': + case 'cutoutB3': + case 'cutoutC3': + case 'cutoutD3': { + x = xSlotPosition + COLUMN_3_X_ADJUSTMENT + width = hasStagingArea + ? STAGING_AREA_FIXTURE_WIDTH + : COLUMN_3_SINGLE_SLOT_FIXTURE_WIDTH + break + } + } + + const y = ySlotPosition + Y_ADJUSTMENT + + const editableStyle = selected ? CONFIG_STYLE_SELECTED : CONFIG_STYLE_EDITABLE + return ( + + handleClickRemove(fixtureLocation, cutoutFixtureId) + : () => {} + } + > + {displayName} + {handleClickRemove != null ? ( + + ) : null} + + + ) +} diff --git a/components/src/hardware-sim/DeckConfigurator/StagingAreaConfigFixture.tsx b/components/src/hardware-sim/DeckConfigurator/StagingAreaConfigFixture.tsx index d1cd3af27d0..8f343977931 100644 --- a/components/src/hardware-sim/DeckConfigurator/StagingAreaConfigFixture.tsx +++ b/components/src/hardware-sim/DeckConfigurator/StagingAreaConfigFixture.tsx @@ -9,24 +9,40 @@ import { COLUMN_3_X_ADJUSTMENT, CONFIG_STYLE_EDITABLE, CONFIG_STYLE_READ_ONLY, + CONFIG_STYLE_SELECTED, FIXTURE_HEIGHT, STAGING_AREA_DISPLAY_NAME, STAGING_AREA_FIXTURE_WIDTH, Y_ADJUSTMENT, } from './constants' -import type { CutoutId, DeckDefinition } from '@opentrons/shared-data' +import type { + CutoutFixtureId, + CutoutId, + DeckDefinition, +} from '@opentrons/shared-data' interface StagingAreaConfigFixtureProps { deckDefinition: DeckDefinition fixtureLocation: CutoutId - handleClickRemove?: (fixtureLocation: CutoutId) => void + cutoutFixtureId: CutoutFixtureId + handleClickRemove?: ( + fixtureLocation: CutoutId, + cutoutFixtureId: CutoutFixtureId + ) => void + selected?: boolean } export function StagingAreaConfigFixture( props: StagingAreaConfigFixtureProps ): JSX.Element { - const { deckDefinition, handleClickRemove, fixtureLocation } = props + const { + deckDefinition, + handleClickRemove, + fixtureLocation, + cutoutFixtureId, + selected = false, + } = props const stagingAreaCutout = deckDefinition.locations.cutouts.find( cutout => cutout.id === fixtureLocation @@ -42,6 +58,7 @@ export function StagingAreaConfigFixture( const x = xSlotPosition + COLUMN_3_X_ADJUSTMENT const y = ySlotPosition + Y_ADJUSTMENT + const editableStyle = selected ? CONFIG_STYLE_SELECTED : CONFIG_STYLE_EDITABLE return ( handleClickRemove(fixtureLocation) + ? () => handleClickRemove(fixtureLocation, cutoutFixtureId) : () => {} } > diff --git a/components/src/hardware-sim/DeckConfigurator/StaticFixture.tsx b/components/src/hardware-sim/DeckConfigurator/StaticFixture.tsx new file mode 100644 index 00000000000..a0fcd1d97d1 --- /dev/null +++ b/components/src/hardware-sim/DeckConfigurator/StaticFixture.tsx @@ -0,0 +1,56 @@ +import * as React from 'react' + +import { Btn, Text } from '../../primitives' +import { TYPOGRAPHY } from '../../ui-style-constants' +import { RobotCoordsForeignObject } from '../Deck/RobotCoordsForeignObject' +import { + CONFIG_STYLE_READ_ONLY, + FIXTURE_HEIGHT, + COLUMN_2_SINGLE_SLOT_FIXTURE_WIDTH, + Y_ADJUSTMENT, + COLUMN_2_X_ADJUSTMENT, +} from './constants' + +import type { CutoutId, DeckDefinition } from '@opentrons/shared-data' + +interface StaticFixtureProps { + deckDefinition: DeckDefinition + fixtureLocation: CutoutId + label: string +} + +/** + * this component allows us to add static labeled fixtures to the center column of a deck + * config map + */ + +export function StaticFixture(props: StaticFixtureProps): JSX.Element { + const { deckDefinition, fixtureLocation, label } = props + + const staticCutout = deckDefinition.locations.cutouts.find( + cutout => cutout.id === fixtureLocation + ) + + /** + * deck definition cutout position is the position of the single slot located within that cutout + * so, to get the position of the cutout itself we must add an adjustment to the slot position + */ + const [xSlotPosition = 0, ySlotPosition = 0] = staticCutout?.position ?? [] + const y = ySlotPosition + Y_ADJUSTMENT + const x = xSlotPosition + COLUMN_2_X_ADJUSTMENT + + return ( + + {}}> + {label} + + + ) +} diff --git a/components/src/hardware-sim/DeckConfigurator/TemperatureModuleFixture.tsx b/components/src/hardware-sim/DeckConfigurator/TemperatureModuleFixture.tsx new file mode 100644 index 00000000000..bda080fbec6 --- /dev/null +++ b/components/src/hardware-sim/DeckConfigurator/TemperatureModuleFixture.tsx @@ -0,0 +1,102 @@ +import * as React from 'react' +import { Icon } from '../../icons' +import { Btn, Text } from '../../primitives' +import { TYPOGRAPHY } from '../../ui-style-constants' +import { COLORS } from '../../helix-design-system' +import { RobotCoordsForeignObject } from '../Deck/RobotCoordsForeignObject' +import { + COLUMN_1_X_ADJUSTMENT, + COLUMN_3_X_ADJUSTMENT, + CONFIG_STYLE_EDITABLE, + CONFIG_STYLE_READ_ONLY, + FIXTURE_HEIGHT, + COLUMN_3_SINGLE_SLOT_FIXTURE_WIDTH, + Y_ADJUSTMENT, + CONFIG_STYLE_SELECTED, +} from './constants' + +import type { + CutoutFixtureId, + CutoutId, + DeckDefinition, +} from '@opentrons/shared-data' + +// TODO(BC, 2024-03-21): This component is almost identical to HeaterShakerFixture, consider consolidating? + +const TEMPERATURE_MODULE_FIXTURE_DISPLAY_NAME = 'Temperature' + +interface TemperatureModuleFixtureProps { + deckDefinition: DeckDefinition + fixtureLocation: CutoutId + cutoutFixtureId: CutoutFixtureId + handleClickRemove?: ( + fixtureLocation: CutoutId, + cutoutFixtureId: CutoutFixtureId + ) => void + selected?: boolean +} + +export function TemperatureModuleFixture( + props: TemperatureModuleFixtureProps +): JSX.Element { + const { + deckDefinition, + handleClickRemove, + fixtureLocation, + cutoutFixtureId, + selected = false, + } = props + + const cutoutDef = deckDefinition.locations.cutouts.find( + cutout => cutout.id === fixtureLocation + ) + + /** + * deck definition cutout position is the position of the single slot located within that cutout + * so, to get the position of the cutout itself we must add an adjustment to the slot position + * the adjustment for x is different for right side/left side + */ + const [xSlotPosition = 0, ySlotPosition = 0] = cutoutDef?.position ?? [] + + const isColumnOne = + fixtureLocation === 'cutoutA1' || + fixtureLocation === 'cutoutB1' || + fixtureLocation === 'cutoutC1' || + fixtureLocation === 'cutoutD1' + const xAdjustment = isColumnOne + ? COLUMN_1_X_ADJUSTMENT + : COLUMN_3_X_ADJUSTMENT + const x = xSlotPosition + xAdjustment + + const y = ySlotPosition + Y_ADJUSTMENT + + const editableStyle = selected ? CONFIG_STYLE_SELECTED : CONFIG_STYLE_EDITABLE + + return ( + + handleClickRemove(fixtureLocation, cutoutFixtureId) + : () => {} + } + > + + {TEMPERATURE_MODULE_FIXTURE_DISPLAY_NAME} + + {handleClickRemove != null ? ( + + ) : null} + + + ) +} diff --git a/components/src/hardware-sim/DeckConfigurator/ThermocyclerFixture.tsx b/components/src/hardware-sim/DeckConfigurator/ThermocyclerFixture.tsx new file mode 100644 index 00000000000..ec2971a6bb6 --- /dev/null +++ b/components/src/hardware-sim/DeckConfigurator/ThermocyclerFixture.tsx @@ -0,0 +1,88 @@ +import * as React from 'react' +import { Icon } from '../../icons' +import { Btn, Text } from '../../primitives' +import { TYPOGRAPHY } from '../../ui-style-constants' +import { COLORS } from '../../helix-design-system' +import { RobotCoordsForeignObject } from '../Deck/RobotCoordsForeignObject' +import { + COLUMN_1_X_ADJUSTMENT, + CONFIG_STYLE_EDITABLE, + CONFIG_STYLE_READ_ONLY, + COLUMN_3_SINGLE_SLOT_FIXTURE_WIDTH, + Y_ADJUSTMENT, + THERMOCYCLER_FIXTURE_HEIGHT, + CONFIG_STYLE_SELECTED, +} from './constants' + +import type { + CutoutFixtureId, + CutoutId, + DeckDefinition, +} from '@opentrons/shared-data' + +interface ThermocyclerFixtureProps { + deckDefinition: DeckDefinition + fixtureLocation: CutoutId + cutoutFixtureId: CutoutFixtureId + handleClickRemove?: ( + fixtureLocation: CutoutId, + cutoutFixtureId: CutoutFixtureId + ) => void + selected?: boolean +} + +const THERMOCYCLER_FIXTURE_DISPLAY_NAME = 'Thermocycler' + +export function ThermocyclerFixture( + props: ThermocyclerFixtureProps +): JSX.Element { + const { + deckDefinition, + handleClickRemove, + fixtureLocation, + cutoutFixtureId, + selected = false, + } = props + + const cutoutDef = deckDefinition.locations.cutouts.find( + cutout => cutout.id === fixtureLocation + ) + + /** + * deck definition cutout position is the position of the single slot located within that cutout + * so, to get the position of the cutout itself we must add an adjustment to the slot position + * the adjustment for x is different for right side/left side + */ + const [xSlotPosition = 0, ySlotPosition = 0] = cutoutDef?.position ?? [] + const x = xSlotPosition + COLUMN_1_X_ADJUSTMENT + const y = ySlotPosition + Y_ADJUSTMENT + + const editableStyle = selected ? CONFIG_STYLE_SELECTED : CONFIG_STYLE_EDITABLE + return ( + + handleClickRemove(fixtureLocation, cutoutFixtureId) + : () => {} + } + > + + {THERMOCYCLER_FIXTURE_DISPLAY_NAME} + + {handleClickRemove != null ? ( + + ) : null} + + + ) +} diff --git a/components/src/hardware-sim/DeckConfigurator/TrashBinConfigFixture.tsx b/components/src/hardware-sim/DeckConfigurator/TrashBinConfigFixture.tsx index 9a9a100d92f..8b6d174c4d6 100644 --- a/components/src/hardware-sim/DeckConfigurator/TrashBinConfigFixture.tsx +++ b/components/src/hardware-sim/DeckConfigurator/TrashBinConfigFixture.tsx @@ -11,23 +11,39 @@ import { CONFIG_STYLE_EDITABLE, CONFIG_STYLE_READ_ONLY, FIXTURE_HEIGHT, - SINGLE_SLOT_FIXTURE_WIDTH, + COLUMN_3_SINGLE_SLOT_FIXTURE_WIDTH, TRASH_BIN_DISPLAY_NAME, Y_ADJUSTMENT, + CONFIG_STYLE_SELECTED, } from './constants' -import type { CutoutId, DeckDefinition } from '@opentrons/shared-data' +import type { + CutoutFixtureId, + CutoutId, + DeckDefinition, +} from '@opentrons/shared-data' interface TrashBinConfigFixtureProps { deckDefinition: DeckDefinition fixtureLocation: CutoutId - handleClickRemove?: (fixtureLocation: CutoutId) => void + cutoutFixtureId: CutoutFixtureId + handleClickRemove?: ( + fixtureLocation: CutoutId, + cutoutFixtureId: CutoutFixtureId + ) => void + selected?: boolean } export function TrashBinConfigFixture( props: TrashBinConfigFixtureProps ): JSX.Element { - const { deckDefinition, handleClickRemove, fixtureLocation } = props + const { + deckDefinition, + handleClickRemove, + fixtureLocation, + cutoutFixtureId, + selected = false, + } = props const trashBinCutout = deckDefinition.locations.cutouts.find( cutout => cutout.id === fixtureLocation @@ -52,9 +68,10 @@ export function TrashBinConfigFixture( const y = ySlotPosition + Y_ADJUSTMENT + const editableStyle = selected ? CONFIG_STYLE_SELECTED : CONFIG_STYLE_EDITABLE return ( handleClickRemove(fixtureLocation) + ? () => handleClickRemove(fixtureLocation, cutoutFixtureId) : () => {} } > diff --git a/components/src/hardware-sim/DeckConfigurator/WasteChuteConfigFixture.tsx b/components/src/hardware-sim/DeckConfigurator/WasteChuteConfigFixture.tsx index 1932fe3674b..13bf151a0d9 100644 --- a/components/src/hardware-sim/DeckConfigurator/WasteChuteConfigFixture.tsx +++ b/components/src/hardware-sim/DeckConfigurator/WasteChuteConfigFixture.tsx @@ -11,18 +11,28 @@ import { CONFIG_STYLE_READ_ONLY, FIXTURE_HEIGHT, STAGING_AREA_FIXTURE_WIDTH, - SINGLE_SLOT_FIXTURE_WIDTH, + COLUMN_3_SINGLE_SLOT_FIXTURE_WIDTH, WASTE_CHUTE_DISPLAY_NAME, Y_ADJUSTMENT, + CONFIG_STYLE_SELECTED, } from './constants' -import type { CutoutId, DeckDefinition } from '@opentrons/shared-data' +import type { + CutoutFixtureId, + CutoutId, + DeckDefinition, +} from '@opentrons/shared-data' interface WasteChuteConfigFixtureProps { deckDefinition: DeckDefinition fixtureLocation: CutoutId - handleClickRemove?: (fixtureLocation: CutoutId) => void + cutoutFixtureId: CutoutFixtureId + handleClickRemove?: ( + fixtureLocation: CutoutId, + cutoutFixtureId: CutoutFixtureId + ) => void hasStagingAreas?: boolean + selected?: boolean } export function WasteChuteConfigFixture( @@ -32,7 +42,9 @@ export function WasteChuteConfigFixture( deckDefinition, handleClickRemove, fixtureLocation, + cutoutFixtureId, hasStagingAreas = false, + selected = false, } = props const wasteChuteCutout = deckDefinition.locations.cutouts.find( @@ -49,10 +61,13 @@ export function WasteChuteConfigFixture( const x = xSlotPosition + COLUMN_3_X_ADJUSTMENT const y = ySlotPosition + Y_ADJUSTMENT + const editableStyle = selected ? CONFIG_STYLE_SELECTED : CONFIG_STYLE_EDITABLE return ( handleClickRemove(fixtureLocation) + ? () => handleClickRemove(fixtureLocation, cutoutFixtureId) : () => {} } > diff --git a/components/src/hardware-sim/DeckConfigurator/constants.ts b/components/src/hardware-sim/DeckConfigurator/constants.ts index 53faef10b7e..c5fab54ab26 100644 --- a/components/src/hardware-sim/DeckConfigurator/constants.ts +++ b/components/src/hardware-sim/DeckConfigurator/constants.ts @@ -9,10 +9,14 @@ import { RESPONSIVENESS, SPACING } from '../../ui-style-constants' * Position is relative to deck definition slot positions and a custom stroke applied to the single slot fixture SVG */ export const FIXTURE_HEIGHT = 102.0 -export const SINGLE_SLOT_FIXTURE_WIDTH = 243.5 +export const THERMOCYCLER_FIXTURE_HEIGHT = 290.0 +export const COLUMN_1_SINGLE_SLOT_FIXTURE_WIDTH = 243.5 +export const COLUMN_2_SINGLE_SLOT_FIXTURE_WIDTH = 159.0 +export const COLUMN_3_SINGLE_SLOT_FIXTURE_WIDTH = 243.5 export const STAGING_AREA_FIXTURE_WIDTH = 314.5 export const COLUMN_1_X_ADJUSTMENT = -100 +export const COLUMN_2_X_ADJUSTMENT = -15.5 export const COLUMN_3_X_ADJUSTMENT = -15.5 export const Y_ADJUSTMENT = -8 @@ -54,3 +58,24 @@ export const CONFIG_STYLE_EDITABLE = css` } } ` + +export const CONFIG_STYLE_SELECTED = css` + ${CONFIG_STYLE_EDITABLE} + background-color: ${COLORS.blue50}; + + &:active { + background-color: ${COLORS.blue60}; + } + + &:hover { + background-color: ${COLORS.blue55}; + } + + &:focus-visible { + border: 3px solid ${COLORS.yellow50}; + background-color: ${COLORS.blue55}; + @media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} { + background-color: ${COLORS.blue60}; + } + } +` diff --git a/components/src/hardware-sim/DeckConfigurator/index.tsx b/components/src/hardware-sim/DeckConfigurator/index.tsx index 9378471d8e0..67e9f972e25 100644 --- a/components/src/hardware-sim/DeckConfigurator/index.tsx +++ b/components/src/hardware-sim/DeckConfigurator/index.tsx @@ -8,6 +8,11 @@ import { TRASH_BIN_ADAPTER_FIXTURE, WASTE_CHUTE_ONLY_FIXTURES, WASTE_CHUTE_STAGING_AREA_FIXTURES, + THERMOCYCLER_V2_FRONT_FIXTURE, + HEATERSHAKER_MODULE_V1_FIXTURE, + TEMPERATURE_MODULE_V2_FIXTURE, + MAGNETIC_BLOCK_V1_FIXTURE, + STAGING_AREA_SLOT_WITH_MAGNETIC_BLOCK_V1_FIXTURE, } from '@opentrons/shared-data' import { COLORS } from '../../helix-design-system' @@ -18,18 +23,33 @@ import { EmptyConfigFixture } from './EmptyConfigFixture' import { StagingAreaConfigFixture } from './StagingAreaConfigFixture' import { TrashBinConfigFixture } from './TrashBinConfigFixture' import { WasteChuteConfigFixture } from './WasteChuteConfigFixture' +import { StaticFixture } from './StaticFixture' -import type { CutoutId, DeckConfiguration } from '@opentrons/shared-data' +import type { + CutoutFixtureId, + CutoutId, + DeckConfiguration, +} from '@opentrons/shared-data' +import { TemperatureModuleFixture } from './TemperatureModuleFixture' +import { HeaterShakerFixture } from './HeaterShakerFixture' +import { MagneticBlockFixture } from './MagneticBlockFixture' +import { ThermocyclerFixture } from './ThermocyclerFixture' interface DeckConfiguratorProps { deckConfig: DeckConfiguration handleClickAdd: (cutoutId: CutoutId) => void - handleClickRemove: (cutoutId: CutoutId) => void + handleClickRemove: ( + cutoutId: CutoutId, + cutoutFixtureId: CutoutFixtureId + ) => void lightFill?: string darkFill?: string - readOnly?: boolean + editableCutoutIds?: CutoutId[] showExpansion?: boolean children?: React.ReactNode + additionalStaticFixtures?: Array<{ location: CutoutId; label: string }> + height?: string + selectedCutoutId?: CutoutId } export function DeckConfigurator(props: DeckConfiguratorProps): JSX.Element { @@ -37,57 +57,58 @@ export function DeckConfigurator(props: DeckConfiguratorProps): JSX.Element { deckConfig, handleClickAdd, handleClickRemove, + additionalStaticFixtures, + children, + selectedCutoutId, lightFill = COLORS.grey35, darkFill = COLORS.black90, - readOnly = false, + editableCutoutIds = deckConfig.map(({ cutoutId }) => cutoutId), showExpansion = true, - children, + height = '455px', } = props const deckDef = getDeckDefFromRobotType(FLEX_ROBOT_TYPE) - // restrict configuration to certain locations - const configurableFixtureLocations: CutoutId[] = [ - 'cutoutA1', - 'cutoutB1', - 'cutoutC1', - 'cutoutD1', - 'cutoutA3', - 'cutoutB3', - 'cutoutC3', - 'cutoutD3', - ] - const configurableDeckConfig = deckConfig.filter(({ cutoutId }) => - configurableFixtureLocations.includes(cutoutId) - ) - - const stagingAreaFixtures = configurableDeckConfig.filter( + const stagingAreaFixtures = deckConfig.filter( ({ cutoutFixtureId }) => cutoutFixtureId === STAGING_AREA_RIGHT_SLOT_FIXTURE ) - const wasteChuteFixtures = configurableDeckConfig.filter( + const wasteChuteFixtures = deckConfig.filter( ({ cutoutFixtureId }) => cutoutFixtureId != null && WASTE_CHUTE_ONLY_FIXTURES.includes(cutoutFixtureId) ) - const wasteChuteStagingAreaFixtures = configurableDeckConfig.filter( + const wasteChuteStagingAreaFixtures = deckConfig.filter( ({ cutoutFixtureId }) => cutoutFixtureId != null && WASTE_CHUTE_STAGING_AREA_FIXTURES.includes(cutoutFixtureId) ) - const emptyFixtures = readOnly - ? [] - : configurableDeckConfig.filter( - ({ cutoutFixtureId }) => - cutoutFixtureId != null && - SINGLE_SLOT_FIXTURES.includes(cutoutFixtureId) - ) - const trashBinFixtures = configurableDeckConfig.filter( + const emptyCutouts = deckConfig.filter( + ({ cutoutFixtureId, cutoutId }) => + editableCutoutIds.includes(cutoutId) && + cutoutFixtureId != null && + SINGLE_SLOT_FIXTURES.includes(cutoutFixtureId) + ) + const trashBinFixtures = deckConfig.filter( ({ cutoutFixtureId }) => cutoutFixtureId === TRASH_BIN_ADAPTER_FIXTURE ) + const thermocyclerFixtures = deckConfig.filter( + ({ cutoutFixtureId }) => cutoutFixtureId === THERMOCYCLER_V2_FRONT_FIXTURE + ) + const heaterShakerFixtures = deckConfig.filter( + ({ cutoutFixtureId }) => cutoutFixtureId === HEATERSHAKER_MODULE_V1_FIXTURE + ) + const temperatureModuleFixtures = deckConfig.filter( + ({ cutoutFixtureId }) => cutoutFixtureId === TEMPERATURE_MODULE_V2_FIXTURE + ) + const magneticBlockFixtures = deckConfig.filter(({ cutoutFixtureId }) => + ([ + MAGNETIC_BLOCK_V1_FIXTURE, + STAGING_AREA_SLOT_WITH_MAGNETIC_BLOCK_V1_FIXTURE, + ] as CutoutFixtureId[]).includes(cutoutFixtureId) + ) return ( {deckDef.locations.cutouts.map(cutout => ( @@ -102,15 +123,19 @@ export function DeckConfigurator(props: DeckConfiguratorProps): JSX.Element { /> ))} - {stagingAreaFixtures.map(({ cutoutId }) => ( + {stagingAreaFixtures.map(({ cutoutId, cutoutFixtureId }) => ( ))} - {emptyFixtures.map(({ cutoutId }) => ( + {emptyCutouts.map(({ cutoutId }) => ( ))} - {wasteChuteFixtures.map(({ cutoutId }) => ( + {wasteChuteFixtures.map(({ cutoutId, cutoutFixtureId }) => ( ))} - {wasteChuteStagingAreaFixtures.map(({ cutoutId }) => ( + {wasteChuteStagingAreaFixtures.map(({ cutoutId, cutoutFixtureId }) => ( ))} - {trashBinFixtures.map(({ cutoutId }) => ( + {trashBinFixtures.map(({ cutoutId, cutoutFixtureId }) => ( + ))} + {temperatureModuleFixtures.map(({ cutoutId, cutoutFixtureId }) => ( + + ))} + {heaterShakerFixtures.map(({ cutoutId, cutoutFixtureId }) => ( + + ))} + {magneticBlockFixtures.map(({ cutoutId, cutoutFixtureId }) => ( + + ))} + {thermocyclerFixtures.map(({ cutoutId, cutoutFixtureId }) => ( + + ))} + {additionalStaticFixtures?.map(staticFixture => ( + ))} s.id === slotName ) if (slotDef == null) { @@ -52,7 +52,7 @@ export function LegacyDeckSlotLocation( const slotPosition = getPositionFromSlotId( slotName, - (ot2DeckDefV4 as unknown) as DeckDefinition + (ot2DeckDefV5 as unknown) as DeckDefinition ) const isFixedTrash = slotName === 'fixedTrash' diff --git a/components/src/icons/Icon.stories.tsx b/components/src/icons/Icon.stories.tsx index 1be5df8581c..9d7b0f1141a 100644 --- a/components/src/icons/Icon.stories.tsx +++ b/components/src/icons/Icon.stories.tsx @@ -1,33 +1,38 @@ import * as React from 'react' - -import { Box, SIZE_3 } from '@opentrons/components' +import { Flex } from '../primitives' +import { SPACING } from '../ui-style-constants' import { ICON_DATA_BY_NAME } from './icon-data' import { Icon as IconComponent } from './Icon' +import type { Meta, StoryObj } from '@storybook/react' -import type { Story, Meta } from '@storybook/react' - -export default { +const meta: Meta = { title: 'Library/Atoms/Icon', + component: IconComponent, argTypes: { name: { + options: Object.keys(ICON_DATA_BY_NAME), control: { type: 'select', - options: Object.keys(ICON_DATA_BY_NAME), }, - defaultValue: 'alert', }, }, decorators: [ Story => ( - + - + ), ], -} as Meta +} -const Template: Story> = args => { - return +export default meta + +type Story = StoryObj + +export const Icon: Story = { + args: { + name: 'alert', + spin: false, + size: '4rem', + }, } -export const Icon = Template.bind({}) -Icon.args = { spin: false } diff --git a/components/src/icons/icon-data.ts b/components/src/icons/icon-data.ts index c805a8bbfba..e4f43123e13 100644 --- a/components/src/icons/icon-data.ts +++ b/components/src/icons/icon-data.ts @@ -632,6 +632,11 @@ export const ICON_DATA_BY_NAME = { 'M8.01487 8.84912C8.47511 8.84912 8.84821 8.47603 8.84821 8.01579C8.84821 7.55555 8.47511 7.18245 8.01487 7.18245C7.55464 7.18245 7.18154 7.55555 7.18154 8.01579C7.18154 8.47603 7.55464 8.84912 8.01487 8.84912Z M8.66654 0.928711V2.36089C11.27 2.66533 13.3354 4.73075 13.6398 7.33418H15.072V8.66751H13.6398C13.3354 11.2709 11.27 13.3363 8.66654 13.6408V15.073H7.3332V13.6408C4.72979 13.3363 2.66437 11.2709 2.35992 8.66751H0.927734V7.33418H2.35992C2.66436 4.73075 4.72978 2.66533 7.3332 2.36089V0.928711H8.66654ZM12.2944 7.33418H11.6184C11.2502 7.33418 10.9518 7.63266 10.9518 8.00085C10.9518 8.36904 11.2502 8.66751 11.6184 8.66751H12.2944C12.0071 10.5336 10.5326 12.008 8.66654 12.2953V11.6194C8.66654 11.2512 8.36806 10.9527 7.99987 10.9527C7.63168 10.9527 7.3332 11.2512 7.3332 11.6194V12.2953C5.46716 12.008 3.99268 10.5336 3.70536 8.66751H4.38132C4.74951 8.66751 5.04798 8.36904 5.04798 8.00085C5.04798 7.63266 4.74951 7.33418 4.38132 7.33418H3.70536C3.99267 5.46812 5.46715 3.99364 7.3332 3.70632V4.38229C7.3332 4.75048 7.63168 5.04896 7.99987 5.04896C8.36806 5.04896 8.66654 4.75048 8.66654 4.38229V3.70632C10.5326 3.99364 12.0071 5.46812 12.2944 7.33418Z', viewBox: '0 0 16 16', }, + send: { + path: + 'M6.96216 26.6667V5.33337L32.2955 16L6.96216 26.6667ZM9.62882 22.6667L25.4288 16L9.62882 9.33337V14L17.6288 16L9.62882 18V22.6667Z', + viewBox: '0 0 32 32', + }, settings: { path: 'M12,15.5A3.5,3.5 0 0,1 8.5,12A3.5,3.5 0 0,1 12,8.5A3.5,3.5 0 0,1 15.5,12A3.5,3.5 0 0,1 12,15.5M19.43,12.97C19.47,12.65 19.5,12.33 19.5,12C19.5,11.67 19.47,11.34 19.43,11L21.54,9.37C21.73,9.22 21.78,8.95 21.66,8.73L19.66,5.27C19.54,5.05 19.27,4.96 19.05,5.05L16.56,6.05C16.04,5.66 15.5,5.32 14.87,5.07L14.5,2.42C14.46,2.18 14.25,2 14,2H10C9.75,2 9.54,2.18 9.5,2.42L9.13,5.07C8.5,5.32 7.96,5.66 7.44,6.05L4.95,5.05C4.73,4.96 4.46,5.05 4.34,5.27L2.34,8.73C2.21,8.95 2.27,9.22 2.46,9.37L4.57,11C4.53,11.34 4.5,11.67 4.5,12C4.5,12.33 4.53,12.65 4.57,12.97L2.46,14.63C2.27,14.78 2.21,15.05 2.34,15.27L4.34,18.73C4.46,18.95 4.73,19.03 4.95,18.95L7.44,17.94C7.96,18.34 8.5,18.68 9.13,18.93L9.5,21.58C9.54,21.82 9.75,22 10,22H14C14.25,22 14.46,21.82 14.5,21.58L14.87,18.93C15.5,18.67 16.04,18.34 16.56,17.94L19.05,18.95C19.27,19.03 19.54,18.95 19.66,18.73L21.66,15.27C21.78,15.05 21.73,14.78 21.54,14.63L19.43,12.97Z', diff --git a/components/src/instrument/InfoItem.tsx b/components/src/instrument/InfoItem.tsx deleted file mode 100644 index 82b5a491a37..00000000000 --- a/components/src/instrument/InfoItem.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import * as React from 'react' - -import styles from './instrument.module.css' - -export interface InfoItemProps { - title: string | null - value: string - className?: string -} - -/** - * Used by `InstrumentInfo` for its titled values. - * But if you're using this, you probably want `LabeledValue` instead. - */ -export function InfoItem(props: InfoItemProps): JSX.Element { - const { title, value, className } = props - - return ( -
- {title != null ?

{title}

: null} - {value} -
- ) -} diff --git a/components/src/instrument/InstrumentInfo.tsx b/components/src/instrument/InstrumentInfo.tsx index d5d26a3b4b4..57ff12e0ed4 100644 --- a/components/src/instrument/InstrumentInfo.tsx +++ b/components/src/instrument/InstrumentInfo.tsx @@ -1,77 +1,103 @@ import * as React from 'react' import { LEFT, RIGHT } from '@opentrons/shared-data' -import { InfoItem } from './InfoItem' -import { InstrumentDiagram } from './InstrumentDiagram' -import styles from './instrument.module.css' import { Flex } from '../primitives' -import { SPACING } from '../ui-style-constants' +import { SPACING, TYPOGRAPHY } from '../ui-style-constants' +import { StyledText } from '../atoms' import { DIRECTION_COLUMN, JUSTIFY_CENTER } from '../styles' +import { InstrumentDiagram } from './InstrumentDiagram' import type { Mount } from '../robot-types' import type { InstrumentDiagramProps } from './InstrumentDiagram' +import styles from './instrument.module.css' + export interface InstrumentInfoProps { /** 'left' or 'right' */ mount: Mount - /** if true, show labels 'LEFT PIPETTE' / 'RIGHT PIPETTE' */ - showMountLabel?: boolean | null /** human-readable description, eg 'p300 Single-channel' */ description: string - /** paired tiprack models */ - tiprackModels?: string[] - /** if disabled, pipette & its info are grayed out */ - isDisabled: boolean /** specs of mounted pipette */ pipetteSpecs?: InstrumentDiagramProps['pipetteSpecs'] | null - /** classes to apply */ - className?: string - /** classes to apply to the info group child */ - infoClassName?: string + /** paired tiprack models */ + tiprackModels?: string[] /** children to display under the info */ children?: React.ReactNode + /** if true, show labels 'LEFT PIPETTE' / 'RIGHT PIPETTE' */ + showMountLabel?: boolean | null } +const MAX_WIDTH = '14rem' + export function InstrumentInfo(props: InstrumentInfoProps): JSX.Element { - const has96Channel = props.pipetteSpecs?.channels === 96 + const { + mount, + showMountLabel, + description, + tiprackModels, + pipetteSpecs, + children, + } = props + + const has96Channel = pipetteSpecs?.channels === 96 return ( - {props.mount === RIGHT && props.pipetteSpecs && ( + {mount === RIGHT && pipetteSpecs ? ( - )} + ) : null} + {/* NOTE: the color is our legacy c-font-dark, which matches the other colors in this component **/} + + + + {showMountLabel && !has96Channel ? `${mount} pipette` : 'pipette'} + + + {description} + + - - - {props.tiprackModels != null - ? props.tiprackModels.map((model, index) => ( - - )) - : null} + + + {'Tip rack'} + +
    + {tiprackModels != null && tiprackModels.length > 0 ? ( + tiprackModels.map((model, index) => ( +
  • + + {model} + +
  • + )) + ) : ( + + {'None'} + + )} +
+
- {props.children} - {props.mount === LEFT && props.pipetteSpecs && ( + {children} + {mount === LEFT && pipetteSpecs ? ( - )} + ) : null}
) } diff --git a/components/src/instrument/__tests__/InstrumentInfo.test.tsx b/components/src/instrument/__tests__/InstrumentInfo.test.tsx new file mode 100644 index 00000000000..bf92c48d4cb --- /dev/null +++ b/components/src/instrument/__tests__/InstrumentInfo.test.tsx @@ -0,0 +1,54 @@ +import * as React from 'react' +import { screen } from '@testing-library/react' +import { describe, beforeEach, it, vi } from 'vitest' +import { LEFT, RIGHT, fixtureP1000SingleV2Specs } from '@opentrons/shared-data' +import { renderWithProviders } from '../../testing/utils' +import { InstrumentInfo } from '../InstrumentInfo' +import { InstrumentDiagram } from '../InstrumentDiagram' + +vi.mock('../InstrumentDiagram') +const render = (props: React.ComponentProps) => { + return renderWithProviders()[0] +} + +describe('InstrumentInfo', () => { + let props: React.ComponentProps + + beforeEach(() => { + props = { + mount: LEFT, + description: 'mock description', + pipetteSpecs: fixtureP1000SingleV2Specs, + tiprackModels: ['mock1', 'mock2'], + showMountLabel: true, + } + vi.mocked(InstrumentDiagram).mockReturnValue( +
mock instrumentDiagram
+ ) + }) + it('renders a p1000 pipette with 2 tiprack models for left mount', () => { + render(props) + screen.getByText('mock instrumentDiagram') + screen.getByText('left pipette') + screen.getByText('mock description') + screen.getByText('Tip rack') + screen.getByText('mock1') + screen.getByText('mock2') + }) + it('renders a p1000 pipette with 1 tiprack model for right mount', () => { + props.mount = RIGHT + props.tiprackModels = ['mock1'] + render(props) + screen.getByText('mock instrumentDiagram') + screen.getByText('right pipette') + screen.getByText('mock description') + screen.getByText('Tip rack') + screen.getByText('mock1') + }) + it('renders none for pip and tiprack if none are selected', () => { + props.pipetteSpecs = undefined + props.tiprackModels = undefined + render(props) + screen.getByText('None') + }) +}) diff --git a/components/src/instrument/index.ts b/components/src/instrument/index.ts index 1153df43ae7..d566fb66e5b 100644 --- a/components/src/instrument/index.ts +++ b/components/src/instrument/index.ts @@ -1,4 +1,3 @@ -export * from './InfoItem' export * from './InstrumentDiagram' export * from './InstrumentGroup' export * from './InstrumentInfo' diff --git a/components/src/lists/TitledList.tsx b/components/src/lists/TitledList.tsx index 58a12d19b6e..4fbe4ab58ee 100644 --- a/components/src/lists/TitledList.tsx +++ b/components/src/lists/TitledList.tsx @@ -2,10 +2,13 @@ import * as React from 'react' import cx from 'classnames' -import styles from './lists.module.css' import { Icon } from '../icons' +import { StyledText } from '../atoms' +import { COLORS } from '../helix-design-system' import type { IconName, IconProps } from '../icons' +import styles from './lists.module.css' + // TODO(bc, 2021-03-31): reconsider whether this belongs in components library // it is bloated with application specific functionality @@ -98,6 +101,15 @@ export function TitledList(props: TitledListProps): JSX.Element { iconProps && iconProps.className ) + let textColor = '' + if (disabled) { + // the below hex code is for our legacy --c-font-disabled to match other text colors + textColor = '#9c9c9c' + } else if (props.selected && !disabled) { + // the below hex code is for our legacy --c-highlight to match other text colors + textColor = '#5fd8ee' + } + return (
)} -

+ {props.title} -

+ {collapsible && (
= { + title: 'Library/Molecules/LocationIcon', argTypes: { iconName: { control: { type: 'select', - options: Object.keys(ICON_DATA_BY_NAME), }, - defaultValue: undefined, + options: Object.keys(ICON_DATA_BY_NAME), }, slotName: { control: { type: 'select', - options: slots, }, - defaultValue: undefined, + options: slots, }, }, component: LocationIcon, - // Note (kk:08/29/2023) this component is located in components so avoid importing const from app parameters: { viewport: { viewports: customViewports, @@ -56,26 +51,25 @@ export default { }, decorators: [ Story => ( - <> + - + ), ], -} as Meta - -const Template: Story> = args => ( - - - -) +} +export default meta +type Story = StoryObj -export const DisplaySlot = Template.bind({}) -DisplaySlot.args = { - slotName: 'A1', +export const DisplaySlot: Story = { + args: { + slotName: 'A1', + iconName: undefined, + }, } -export const DisplayIcon = Template.bind({}) -DisplayIcon.args = { - iconName: 'ot-temperature-v2', +export const DisplayIcon: Story = { + args: { + iconName: 'ot-temperature-v2', + }, } diff --git a/components/src/molecules/ParametersTable/InfoScreen.tsx b/components/src/molecules/ParametersTable/InfoScreen.tsx index b9798f828e3..17b4c792a98 100644 --- a/components/src/molecules/ParametersTable/InfoScreen.tsx +++ b/components/src/molecules/ParametersTable/InfoScreen.tsx @@ -8,14 +8,35 @@ import { Flex } from '../../primitives' import { ALIGN_CENTER, DIRECTION_COLUMN } from '../../styles' interface InfoScreenProps { - contentType: 'parameters' | 'moduleControls' + contentType: 'parameters' | 'moduleControls' | 'runNotStarted' | 'labware' + t?: any } -export function InfoScreen({ contentType }: InfoScreenProps): JSX.Element { - const bodyText = - contentType === 'parameters' - ? 'No parameters specified in this protocol' - : 'Connect modules to see controls' +export function InfoScreen({ contentType, t }: InfoScreenProps): JSX.Element { + let bodyText: string = '' + switch (contentType) { + case 'parameters': + bodyText = + t != null + ? t('no_parameters_specified_in_protocol') + : 'No parameters specified in this protocol' + break + case 'moduleControls': + bodyText = + t != null + ? t('connect_modules_for_controls') + : 'Connect modules to see controls' + break + case 'runNotStarted': + bodyText = t != null ? t('run_never_started') : 'Run was never started' + break + case 'labware': + bodyText = 'No labware specified in this protocol' + break + default: + bodyText = contentType + } + return ( { screen.getByText('Connect modules to see controls') }) + it('should render text and icon with proper color - run not started', () => { + props = { + contentType: 'runNotStarted', + } + render(props) + screen.getByLabelText('alert') + screen.getByText('Run was never started') + }) + + it('should render text and icon with proper color - labware', () => { + props = { + contentType: 'labware', + } + render(props) + screen.getByLabelText('alert') + screen.getByText('No labware specified in this protocol') + }) + it('should have proper styles', () => { render(props) expect(screen.getByTestId('InfoScreen_parameters')).toHaveStyle( diff --git a/components/src/molecules/RoundTab.stories.tsx b/components/src/molecules/RoundTab.stories.tsx index be08c541743..fc0821c793d 100644 --- a/components/src/molecules/RoundTab.stories.tsx +++ b/components/src/molecules/RoundTab.stories.tsx @@ -1,55 +1,80 @@ import * as React from 'react' import { SPACING, TYPOGRAPHY } from '../ui-style-constants' -import { Flex, Text } from '../primitives' -import { DIRECTION_ROW } from '../styles' -import { RoundTab } from './RoundTab' -import type { Story, Meta } from '@storybook/react' +import { Flex } from '../primitives' +import { StyledText } from '../atoms/StyledText' +import { DIRECTION_COLUMN, DIRECTION_ROW } from '../styles' +import { RoundTab as RoundTabComponent } from './RoundTab' +import type { Meta, StoryObj } from '@storybook/react' -export default { +const meta: Meta = { title: 'Library/Molecules/RoundTab', - component: RoundTab, -} as Meta - -const Template: Story< - React.ComponentProps -> = (): JSX.Element => { - const [step, setStep] = React.useState<'details' | 'pipette' | 'module'>( - 'details' - ) + component: RoundTabComponent, + decorators: [Story => ], +} +export default meta + +const Tabs = (): JSX.Element => { + const [step, setStep] = React.useState< + 'setup' | 'parameters' | 'module controls' | 'run preview' + >('setup') return ( - setStep('details')} - > - - {'Protocol Name and Description'} - - - - setStep('pipette')} + + setStep('setup')} + tabName={'setup'} + > + + {'Setup'} + + + + setStep('parameters')} + > + + {'Parameters'} + + + + setStep('module controls')} + > + + {'Module Controls'} + + + + setStep('run preview')} + > + + {'Run Preview'} + + + + - - {'Pipette Selection'} - - - - setStep('module')}> - - {'Module Selection'} - - + {step} + ) } -export const Basic = Template.bind({}) -Basic.args = {} +type Story = StoryObj + +export const RoundTab: Story = { + args: {}, +} diff --git a/components/src/styles/flexbox.ts b/components/src/styles/flexbox.ts index bc588372e96..2c36936b200 100644 --- a/components/src/styles/flexbox.ts +++ b/components/src/styles/flexbox.ts @@ -1,6 +1,7 @@ export const FLEX_NONE = 'none' export const FLEX_AUTO = 'auto' export const FLEX_MIN_CONTENT = 'min-content' +export const FLEX_MAX_CONTENT = 'max-content' export const ALIGN_NORMAL = 'normal' export const ALIGN_START = 'start' diff --git a/components/src/ui-style-constants/spacing.ts b/components/src/ui-style-constants/spacing.ts index bdd4dbcab26..2fd0e0c9ecd 100644 --- a/components/src/ui-style-constants/spacing.ts +++ b/components/src/ui-style-constants/spacing.ts @@ -9,6 +9,7 @@ export const spacing20 = '1.25rem' as const // 20px export const spacing24 = '1.5rem' as const // 24px export const spacing32 = '2rem' as const // 32px export const spacing40 = '2.5rem' as const // 40px +export const spacing44 = '2.75rem' as const // 44px export const spacing48 = '3rem' as const // 48px export const spacing60 = '3.75rem' as const // 60px export const spacing68 = '4.25rem' as const // 68px diff --git a/components/webpack.config.js b/components/webpack.config.js deleted file mode 100644 index 648eaee3432..00000000000 --- a/components/webpack.config.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict' - -const path = require('path') -const { rules } = require('@opentrons/webpack-config') - -const ENTRY_INDEX = path.join(__dirname, 'src/barrel.ts') -const OUTPUT_PATH = path.join(__dirname, 'lib') - -module.exports = { - target: 'web', - entry: { index: ENTRY_INDEX }, - output: { - path: OUTPUT_PATH, - filename: 'opentrons-components.js', - library: '@opentrons/components', - libraryTarget: 'umd', - globalObject: 'this', - }, - mode: 'production', - module: { rules: [rules.js] }, - resolve: { - extensions: ['.wasm', '.mjs', '.js', '.ts', '.tsx', '.json'], - }, - externals: { - react: { - root: 'React', - commonjs2: 'react', - commonjs: 'react', - amd: 'react', - }, - 'react-dom': { - root: 'ReactDOM', - commonjs2: 'react-dom', - commonjs: 'react-dom', - amd: 'react-dom', - }, - }, -} diff --git a/discovery-client/vite.config.ts b/discovery-client/vite.config.ts index 7cbd9ae43c3..c67977a8359 100644 --- a/discovery-client/vite.config.ts +++ b/discovery-client/vite.config.ts @@ -1,13 +1,14 @@ -import { versionForProject } from '../scripts/git-version' +import { versionForProject } from '../scripts/git-version.mjs' import pkg from './package.json' import path from 'path' -import { UserConfig, defineConfig } from 'vite' +import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import postCssImport from 'postcss-import' import postCssApply from 'postcss-apply' import postColorModFunction from 'postcss-color-mod-function' import postCssPresetEnv from 'postcss-preset-env' import lostCss from 'lost' +import type { UserConfig } from 'vite' export default defineConfig( async (): Promise => { diff --git a/discovery-client/webpack.config.js b/discovery-client/webpack.config.js deleted file mode 100644 index c15a3bae1c2..00000000000 --- a/discovery-client/webpack.config.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict' - -const path = require('path') -const webpackMerge = require('webpack-merge') -const { DefinePlugin } = require('webpack') -const { nodeBaseConfig } = require('@opentrons/webpack-config') -const { versionForProject } = require('../scripts/git-version') - -const ENTRY_INDEX = path.join(__dirname, 'src/index.ts') -const ENTRY_CLI = path.join(__dirname, 'src/cli.ts') -const OUTPUT_PATH = path.join(__dirname, 'lib') -const project = process.env.OPENTRONS_PROJECT ?? 'robot-stack' - -module.exports = async () => - webpackMerge(nodeBaseConfig, { - entry: { - index: ENTRY_INDEX, - cli: ENTRY_CLI, - }, - output: { path: OUTPUT_PATH }, - plugins: [ - new DefinePlugin({ - _PKG_VERSION_: JSON.stringify(await versionForProject(project)), - }), - ], - }) diff --git a/hardware-testing/Makefile b/hardware-testing/Makefile index a48b794977f..afe2a57c2ee 100755 --- a/hardware-testing/Makefile +++ b/hardware-testing/Makefile @@ -257,9 +257,11 @@ scp $(ssh_helper_ot3) $(4) root@$(1):/tmp/ ssh $(ssh_helper_ot3) root@$(1) \ "function cleanup () { (rm -rf /tmp/$(4) || true) && mount -o remount,ro / ; } ;\ mount -o remount,rw / &&\ -(unzip -o /tmp/$(4) -d /usr/lib/firmware || cleanup) &&\ +(unzip -o /tmp/$(5) -d /usr/lib/firmware || cleanup) &&\ python3 -m json.tool /usr/lib/firmware/opentrons-firmware.json &&\ -cleanup" +cleanup &&\ +echo "Restarting robot server" &&\ +systemctl restart opentrons-robot-server" endef .PHONY: sync-sw-ot3 @@ -284,7 +286,7 @@ remove-patches-fixture: .PHONY: sync-fw-ot3 sync-fw-ot3: - $(call push-and-update-fw,$(host),$(ssh_key),$(ssh_opts),$(zip)) + $(call push-and-update-fw,$(host),$(ssh_key),$(ssh_opts),$(zip),$(notdir $(zip))) .PHONY: sync-ot3 sync-ot3: sync-sw-ot3 sync-fw-ot3 diff --git a/hardware-testing/hardware_testing/gravimetric/config.py b/hardware-testing/hardware_testing/gravimetric/config.py index 993e8716a92..f80d87d7124 100644 --- a/hardware-testing/hardware_testing/gravimetric/config.py +++ b/hardware-testing/hardware_testing/gravimetric/config.py @@ -5,6 +5,7 @@ from enum import Enum from opentrons.config.types import LiquidProbeSettings, OutputOptions from opentrons.protocol_api.labware import Well +from opentrons.hardware_control.types import InstrumentProbeType class ConfigType(Enum): @@ -197,7 +198,7 @@ def _get_liquid_probe_settings( aspirate_while_sensing=False, auto_zero_sensor=True, num_baseline_reads=10, - data_file="/data/testing_data/pressure.csv", + data_files={InstrumentProbeType.PRIMARY: "/data/testing_data/pressure.csv"}, ) diff --git a/hardware-testing/hardware_testing/gravimetric/helpers.py b/hardware-testing/hardware_testing/gravimetric/helpers.py index 7844f8d8d5e..135eced1f5d 100644 --- a/hardware-testing/hardware_testing/gravimetric/helpers.py +++ b/hardware-testing/hardware_testing/gravimetric/helpers.py @@ -434,7 +434,9 @@ def _load_pipette( # NOTE: 8ch QC testing means testing 1 channel at a time, # so we need to decrease the pick-up current to work with 1 tip. if pipette.channels == 8 and not increment and not photometric: - pipette.configure_nozzle_layout(NozzleLayout.SINGLE, "A1") + pipette._core.configure_nozzle_layout( + style=NozzleLayout.SINGLE, primary_nozzle="A1", front_right_nozzle="A1" + ) # override deck conflict checking cause we specially lay out our tipracks DeckConflit.check_safe_for_pipette_movement = ( _override_check_safe_for_pipette_movement diff --git a/hardware-testing/hardware_testing/liquid_sense/__main__.py b/hardware-testing/hardware_testing/liquid_sense/__main__.py index 10db70e67c8..af83c031436 100644 --- a/hardware-testing/hardware_testing/liquid_sense/__main__.py +++ b/hardware-testing/hardware_testing/liquid_sense/__main__.py @@ -80,7 +80,6 @@ class RunArgs: pipette: InstrumentContext pipette_tag: str git_description: str - robot_serial: str recorder: GravimetricRecorder pipette_volume: int pipette_channels: int @@ -140,7 +139,6 @@ def _get_protocol_context(cls, args: argparse.Namespace) -> ProtocolContext: def build_run_args(cls, args: argparse.Namespace) -> "RunArgs": """Build.""" _ctx = RunArgs._get_protocol_context(args) - robot_serial = helpers._get_robot_serial(_ctx.is_simulating()) run_id, start_time = create_run_id_and_start_time() environment_sensor = asair_sensor.BuildAsairSensor( _ctx.is_simulating() or args.ignore_env @@ -161,7 +159,10 @@ def build_run_args(cls, args: argparse.Namespace) -> "RunArgs": pipette_tag = helpers._get_tag_from_pipette(pipette, False, False) if args.trials == 0: - trials = 10 + if args.channels < 96: + trials = 10 + else: + trials = 7 else: trials = args.trials @@ -195,7 +196,6 @@ def build_run_args(cls, args: argparse.Namespace) -> "RunArgs": # go ahead and store the meta data now store_serial_numbers( report, - robot_serial, pipette_tag, scale.read_serial_number(), environment_sensor.get_serial(), @@ -220,7 +220,6 @@ def build_run_args(cls, args: argparse.Namespace) -> "RunArgs": pipette=pipette, pipette_tag=pipette_tag, git_description=git_description, - robot_serial=robot_serial, recorder=recorder, pipette_volume=args.pipette, pipette_channels=args.channels, @@ -270,6 +269,7 @@ def build_run_args(cls, args: argparse.Namespace) -> "RunArgs": args = parser.parse_args() run_args = RunArgs.build_run_args(args) + exit_error = os.EX_OK try: if not run_args.ctx.is_simulating(): data_dir = get_testing_data_directory() @@ -292,6 +292,7 @@ def build_run_args(cls, args: argparse.Namespace) -> "RunArgs": except Exception as e: ui.print_info(f"got error {e}") ui.print_info(traceback.format_exc()) + exit_error = 1 finally: if run_args.recorder is not None: ui.print_info("ending recording") @@ -314,4 +315,4 @@ def build_run_args(cls, args: argparse.Namespace) -> "RunArgs": run_args.ctx.cleanup() if not args.simulate: helpers_ot3.restart_server_ot3() - os._exit(os.EX_OK) + os._exit(exit_error) diff --git a/hardware-testing/hardware_testing/liquid_sense/execute.py b/hardware-testing/hardware_testing/liquid_sense/execute.py index 1fc95d62d44..46368568bf2 100644 --- a/hardware-testing/hardware_testing/liquid_sense/execute.py +++ b/hardware-testing/hardware_testing/liquid_sense/execute.py @@ -176,45 +176,57 @@ def run(tip: int, run_args: RunArgs) -> None: lpc_offset = run_args.dial_indicator.read_stable() run_args.pipette._retract() - def _get_baseline() -> float: - run_args.pipette.pick_up_tip(tips.pop(0)) - liquid_height = _jog_to_find_liquid_height( - run_args.ctx, run_args.pipette, test_well - ) - target_height = test_well.bottom(liquid_height).point.z - - run_args.pipette._retract() - # tip_offset = 0.0 + def _get_tip_offset() -> float: + tip_offset = 0.0 if run_args.dial_indicator is not None: run_args.pipette.move_to(dial_well.top()) tip_offset = run_args.dial_indicator.read_stable() run_args.pipette._retract() - if run_args.return_tip: - run_args.pipette.return_tip() - else: - run_args.pipette.drop_tip() - - env_data = run_args.environment_sensor.get_reading() + return tip_offset - store_baseline_trial( - run_args.test_report, - tip, - target_height, - env_data.relative_humidity, - env_data.temperature, - test_well.top().point.z - target_height, - tip_offset - lpc_offset, + def _get_target_height() -> float: + run_args.pipette.pick_up_tip(tips[0]) + del tips[: run_args.pipette_channels] + liquid_height = _jog_to_find_liquid_height( + run_args.ctx, run_args.pipette, test_well ) + target_height = test_well.bottom(liquid_height).point.z + run_args.pipette._retract() return target_height + target_height = _get_target_height() + tip_offset = _get_tip_offset() + + if run_args.return_tip: + run_args.pipette.return_tip() + else: + run_args.pipette.drop_tip() + + env_data = run_args.environment_sensor.get_reading() + + store_baseline_trial( + run_args.test_report, + tip, + target_height, + env_data.relative_humidity, + env_data.temperature, + test_well.top().point.z - target_height, + tip_offset - lpc_offset, + ) + trials_before_jog = run_args.trials_before_jog - tip_offset = 0.0 + for trial in range(run_args.trials): - if trial % trials_before_jog == 0: - tip_offset = _get_baseline() + if trial > 0 and trial % trials_before_jog == 0: + target_height = _get_target_height() + if run_args.return_tip: + run_args.pipette.return_tip() + else: + run_args.pipette.drop_tip() ui.print_info(f"Picking up {tip}ul tip") - run_args.pipette.pick_up_tip(tips.pop(0)) + run_args.pipette.pick_up_tip(tips[0]) + del tips[: run_args.pipette_channels] run_args.pipette.move_to(test_well.top()) start_pos = hw_api.current_position_ot3(OT3Mount.LEFT) @@ -223,7 +235,6 @@ def _get_baseline() -> float: run_args.pipette.blow_out() tip_length_offset = 0.0 if run_args.dial_indicator is not None: - run_args.pipette._retract() run_args.pipette.move_to(dial_well.top()) tip_length_offset = tip_offset - run_args.dial_indicator.read_stable() @@ -255,6 +266,7 @@ def _get_baseline() -> float: start_pos[Axis.Z_L] - end_pos[Axis.Z_L], plunger_start - end_pos[Axis.P_L], tip_length_offset, + target_height, ) ui.print_info( f"\n\n Z axis start pos {start_pos[Axis.Z_L]} end pos {end_pos[Axis.Z_L]}" @@ -274,9 +286,17 @@ def _run_trial(run_args: RunArgs, tip: int, well: Well, trial: int) -> float: run_args.pipette_channels ][tip] data_dir = get_testing_data_directory() - data_filename = f"pressure_sensor_data-trial{trial}-tip{tip}.csv" - data_file = f"{data_dir}/{run_args.name}/{run_args.run_id}/{data_filename}" - ui.print_info(f"logging pressure data to {data_file}") + probes: List[InstrumentProbeType] = [InstrumentProbeType.PRIMARY] + probe_target: InstrumentProbeType = InstrumentProbeType.PRIMARY + if run_args.pipette_channels > 1: + probes.append(InstrumentProbeType.SECONDARY) + probe_target = InstrumentProbeType.BOTH + data_files: Dict[InstrumentProbeType, str] = {} + for probe in probes: + data_filename = f"pressure_sensor_data-trial{trial}-tip{tip}-{probe.name}.csv" + data_file = f"{data_dir}/{run_args.name}/{run_args.run_id}/{data_filename}" + ui.print_info(f"logging pressure data to {data_file}") + data_files[probe] = data_file plunger_speed = ( lqid_cfg["plunger_speed"] @@ -295,13 +315,13 @@ def _run_trial(run_args: RunArgs, tip: int, well: Well, trial: int) -> float: aspirate_while_sensing=run_args.aspirate, auto_zero_sensor=True, num_baseline_reads=10, - data_file=data_file, + data_files=data_files, ) hw_mount = OT3Mount.LEFT if run_args.pipette.mount == "left" else OT3Mount.RIGHT run_args.recorder.set_sample_tag(f"trial-{trial}-{tip}ul") # TODO add in stuff for secondary probe - height = hw_api.liquid_probe(hw_mount, lps, InstrumentProbeType.PRIMARY) + height = hw_api.liquid_probe(hw_mount, lps, probe_target) ui.print_info(f"Trial {trial} complete") run_args.recorder.clear_sample_tag() return height diff --git a/hardware-testing/hardware_testing/liquid_sense/post_process.py b/hardware-testing/hardware_testing/liquid_sense/post_process.py index 20e46ed746a..a5b7c7f47cb 100644 --- a/hardware-testing/hardware_testing/liquid_sense/post_process.py +++ b/hardware-testing/hardware_testing/liquid_sense/post_process.py @@ -21,6 +21,25 @@ } +def _get_pressure_results(result_file: str) -> Tuple[float, float, float, List[float]]: + z_velocity: float = 0.0 + p_velocity: float = 0.0 + threshold: float = 0.0 + pressures: List[float] = [] + with open(result_file, newline="") as trial_csv: + trial_reader = csv.reader(trial_csv) + i = 0 + for row in trial_reader: + if i == 1: + z_velocity = float(row[2]) + p_velocity = float(row[3]) + threshold = float(row[4]) + if i > 1: + pressures.append(float(row[1])) + i += 1 + return z_velocity, p_velocity, threshold, pressures + + def process_csv_directory( # noqa: C901 data_directory: str, tips: List[int], trials: int, make_graph: bool = False ) -> None: @@ -29,15 +48,22 @@ def process_csv_directory( # noqa: C901 summary: str = [f for f in csv_files if "CSVReport" in f][0] final_report_file: str = f"{data_directory}/final_report.csv" # initialize our data structs - pressure_csvs = [f for f in csv_files if "pressure_sensor_data" in f] - pressure_results_files: Dict[int, List[str]] = {} - pressure_results: Dict[int, Dict[int, List[float]]] = {} + primary_pressure_csvs = [f for f in csv_files if "PRIMARY" in f] + secondary_pressure_csvs = [f for f in csv_files if "SECONDARY" in f] + primary_pressure_results_files: Dict[int, List[str]] = {} + secondary_pressure_results_files: Dict[int, List[str]] = {} + pressure_results: Dict[int, Dict[int, List[Tuple[float, float]]]] = {} results_settings: Dict[int, Dict[int, Tuple[float, float, float]]] = {} tip_offsets: Dict[int, List[float]] = {} p_offsets: Dict[int, List[float]] = {} meniscus_travel: float = 0 for tip in tips: - pressure_results_files[tip] = [f for f in pressure_csvs if f"tip{tip}" in f] + primary_pressure_results_files[tip] = [ + f for f in primary_pressure_csvs if f"tip{tip}" in f + ] + secondary_pressure_results_files[tip] = [ + f for f in secondary_pressure_csvs if f"tip{tip}" in f + ] pressure_results[tip] = {} results_settings[tip] = {} tip_offsets[tip] = [] @@ -50,22 +76,35 @@ def process_csv_directory( # noqa: C901 # read in all of the pressure csvs into one big struct so we can process them for tip in tips: for trial in range(trials): - with open( - f"{data_directory}/{pressure_results_files[tip][trial]}", newline="" - ) as trial_csv: - trial_reader = csv.reader(trial_csv) - i = 0 - for row in trial_reader: - if i == 1: - results_settings[tip][trial] = ( - float(row[2]), - float(row[3]), - float(row[4]), - ) - if i > 1: - pressure_results[tip][trial].append(float(row[1])) - i += 1 - max_results_len = max([i - 2, max_results_len]) + z_velocity: float = 0.0 + p_velocity: float = 0.0 + threshold: float = 0.0 + primary_pressures: List[float] = [] + secondary_pressures: List[float] = [] + if trial < len(primary_pressure_results_files[tip]): + ( + z_velocity, + p_velocity, + threshold, + primary_pressures, + ) = _get_pressure_results( + f"{data_directory}/{primary_pressure_results_files[tip][trial]}" + ) + if trial < len(secondary_pressure_results_files[tip]): + ( + z_velocity, + p_velocity, + threshold, + secondary_pressures, + ) = _get_pressure_results( + f"{data_directory}/{secondary_pressure_results_files[tip][trial]}" + ) + results_settings[tip][trial] = (z_velocity, p_velocity, threshold) + for i in range(max(len(primary_pressures), len(secondary_pressures))): + p = primary_pressures[i] if i < len(primary_pressures) else 0.0 + s = secondary_pressures[i] if i < len(secondary_pressures) else 0.0 + pressure_results[tip][trial].append((p, s)) + max_results_len = max([len(pressure_results[tip][trial]), max_results_len]) # start writing the final report csv with open(f"{data_directory}/{summary}", newline="") as summary_csv: summary_reader = csv.reader(summary_csv) @@ -76,11 +115,11 @@ def process_csv_directory( # noqa: C901 for row in summary_reader: final_report_writer.writerow(row) s += 1 - if s == 45: + if s == 44: meniscus_travel = float(row[6]) - if s >= 46 and s < 46 + (trials * len(tips)): + if s >= 45 and s < 45 + (trials * len(tips)): # while processing this grab the tip offsets from the summary - tip_offsets[tips[int((s - 46) / trials)]].append(float(row[8])) + tip_offsets[tips[int((s - 45) / trials)]].append(float(row[8])) # summary_reader.line_num is the last line in the summary that has text pressures_start_line = summary_reader.line_num + 3 # calculate where the start and end of each block of data we want to graph @@ -102,7 +141,12 @@ def process_csv_directory( # noqa: C901 pressure_header_row = ["time", ""] for i in range(trials): pressure_header_row.extend( - [f"pressure T{i+1}", f"z_travel T{i+1}", f"p_travel T{i+1}"] + [ + f"primary pressure T{i+1}", + f"secondary pressure T{i+1}", + f"z_travel T{i+1}", + f"p_travel T{i+1}", + ] ) # we want to line up the z height's of each trial at time==0 @@ -153,9 +197,11 @@ def process_csv_directory( # noqa: C901 pressure_row.append("") for trial in range(trials): if i < len(pressure_results[tip][trial]): - pressure_row.append(f"{pressure_results[tip][trial][i]}") + pressure_row.append(f"{pressure_results[tip][trial][i][0]}") + pressure_row.append(f"{pressure_results[tip][trial][i][1]}") else: pressure_row.append("") + pressure_row.append("") pressure_row.append( f"{results_settings[tip][trial][0] * time - tip_offsets[tip][trial]}" ) diff --git a/hardware-testing/hardware_testing/liquid_sense/report.py b/hardware-testing/hardware_testing/liquid_sense/report.py index bca898e79c7..84d5141fd8b 100644 --- a/hardware-testing/hardware_testing/liquid_sense/report.py +++ b/hardware-testing/hardware_testing/liquid_sense/report.py @@ -41,7 +41,6 @@ def build_serial_number_section() -> CSVSection: return CSVSection( title="SERIAL-NUMBERS", lines=[ - CSVLine("robot", [str]), CSVLine("git_description", [str]), CSVLine("pipette", [str]), CSVLine("scale", [str]), @@ -71,7 +70,7 @@ def build_config_section() -> CSVSection: def build_trials_section(trials: int, tips: List[int]) -> CSVSection: """Build section.""" lines: List[Union[CSVLine, CSVLineRepeating]] = [ - CSVLine("trial_number", [str, str, str, str, str, str, str, str]) + CSVLine("trial_number", [str, str, str, str, str, str, str, str, str]) ] lines.extend( [ @@ -86,7 +85,7 @@ def build_trials_section(trials: int, tips: List[int]) -> CSVSection: [ CSVLine( f"trial-{t + 1}-{tip}ul", - [float, float, float, float, float, float, float, float], + [float, float, float, float, float, float, float, float, float], ) for tip in tips for t in range(trials) @@ -116,14 +115,12 @@ def build_results_section(tips: List[int]) -> CSVSection: def store_serial_numbers( report: CSVReport, - robot: str, pipette: str, scale: str, environment: str, git_description: str, ) -> None: """Report serial numbers.""" - report("SERIAL-NUMBERS", "robot", [robot]) report("SERIAL-NUMBERS", "git_description", [git_description]) report("SERIAL-NUMBERS", "pipette", [pipette]) report("SERIAL-NUMBERS", "scale", [scale]) @@ -195,6 +192,7 @@ def store_trial( z_travel: float, plunger_travel: float, tip_length_offset: float, + target_height: float, ) -> None: """Report Trial.""" report( @@ -209,6 +207,7 @@ def store_trial( plunger_travel, tip_length_offset, height + tip_length_offset, + target_height, ], ) @@ -258,6 +257,7 @@ def build_ls_report( "plunger_travel", "tip_length_offset", "adjusted_height", + "target_height", ], ) return report diff --git a/hardware-testing/hardware_testing/production_qc/pipette_assembly_qc_ot3/__main__.py b/hardware-testing/hardware_testing/production_qc/pipette_assembly_qc_ot3/__main__.py index 1ec595974b4..5e482afa6e7 100644 --- a/hardware-testing/hardware_testing/production_qc/pipette_assembly_qc_ot3/__main__.py +++ b/hardware-testing/hardware_testing/production_qc/pipette_assembly_qc_ot3/__main__.py @@ -1386,7 +1386,7 @@ async def _test_liquid_probe( aspirate_while_sensing=False, # FIXME: I heard this doesn't work auto_zero_sensor=True, # TODO: when would we want to adjust this? num_baseline_reads=10, # TODO: when would we want to adjust this? - data_file="", # FIXME: remove + data_files=None, ) end_z = await api.liquid_probe(mount, probe_settings, probe=probe) if probe == InstrumentProbeType.PRIMARY: diff --git a/hardware-testing/hardware_testing/protocols/liquid_sense_lpc/liquid_sense_ot3_p1000_96.py b/hardware-testing/hardware_testing/protocols/liquid_sense_lpc/liquid_sense_ot3_p1000_96.py index 02644b314a4..09aa4954958 100644 --- a/hardware-testing/hardware_testing/protocols/liquid_sense_lpc/liquid_sense_ot3_p1000_96.py +++ b/hardware-testing/hardware_testing/protocols/liquid_sense_lpc/liquid_sense_ot3_p1000_96.py @@ -8,9 +8,9 @@ SLOT_DIAL = 5 SLOTS_TIPRACK = { # TODO: add slot 12 when tipracks are disposable - 50: [2, 3, 6, 7, 8, 9, 10, 11], - 200: [2, 3, 6, 7, 8, 9, 10, 11], # NOTE: ignored during calibration - 1000: [2, 3, 6, 7, 8, 9, 10, 11], # NOTE: ignored during calibration + 50: [1, 2, 3, 6, 7, 8, 9, 10, 11], + 200: [1, 2, 3, 6, 7, 8, 9, 10, 11], # NOTE: ignored during calibration + 1000: [1, 2, 3, 6, 7, 8, 9, 10, 11], # NOTE: ignored during calibration } LABWARE_ON_SCALE = "nest_1_reservoir_195ml" diff --git a/hardware-testing/hardware_testing/scripts/abr_asair_sensor.py b/hardware-testing/hardware_testing/scripts/abr_asair_sensor.py index aa66f230409..33195dacd5a 100644 --- a/hardware-testing/hardware_testing/scripts/abr_asair_sensor.py +++ b/hardware-testing/hardware_testing/scripts/abr_asair_sensor.py @@ -25,7 +25,7 @@ def __init__(self, robot: str, duration: int, frequency: int) -> None: test_name = "ABR-Environment-Monitoring" run_id = data.create_run_id() file_name = data.create_file_name(test_name, run_id, robot) - sensor = asair_sensor.BuildAsairSensor(False, True) + sensor = asair_sensor.BuildAsairSensor(False, False) print(sensor) env_data = sensor.get_reading() header = [ diff --git a/hardware/opentrons_hardware/drivers/binary_usb/binary_messenger.py b/hardware/opentrons_hardware/drivers/binary_usb/binary_messenger.py index 49c1584526d..4c54e5a8632 100644 --- a/hardware/opentrons_hardware/drivers/binary_usb/binary_messenger.py +++ b/hardware/opentrons_hardware/drivers/binary_usb/binary_messenger.py @@ -196,7 +196,6 @@ async def _read_task(self) -> None: if filter and not filter( BinaryMessageId(message_definition.message_id.value) ): - log.debug("message ignored by filter") continue listener(message_definition) if ( diff --git a/hardware/opentrons_hardware/drivers/can_bus/can_messenger.py b/hardware/opentrons_hardware/drivers/can_bus/can_messenger.py index 4446b3b0683..c0b49e376bb 100644 --- a/hardware/opentrons_hardware/drivers/can_bus/can_messenger.py +++ b/hardware/opentrons_hardware/drivers/can_bus/can_messenger.py @@ -379,7 +379,6 @@ async def _read_task(self) -> None: handled = False for listener, filter in self._listeners.values(): if filter and not filter(message.arbitration_id): - log.debug("message ignored by filter") continue listener(message_definition(payload=build), message.arbitration_id) # type: ignore[arg-type] handled = True diff --git a/hardware/opentrons_hardware/firmware_bindings/constants.py b/hardware/opentrons_hardware/firmware_bindings/constants.py index 25e5084147c..f569b0d8ff4 100644 --- a/hardware/opentrons_hardware/firmware_bindings/constants.py +++ b/hardware/opentrons_hardware/firmware_bindings/constants.py @@ -338,6 +338,8 @@ class SensorId(int, Enum): S0 = 0x0 S1 = 0x1 + UNUSED = 0x2 + BOTH = 0x3 @unique diff --git a/hardware/opentrons_hardware/hardware_control/motor_enable_disable.py b/hardware/opentrons_hardware/hardware_control/motor_enable_disable.py index 9928b841da9..32897d16679 100644 --- a/hardware/opentrons_hardware/hardware_control/motor_enable_disable.py +++ b/hardware/opentrons_hardware/hardware_control/motor_enable_disable.py @@ -122,7 +122,9 @@ def _listener(message: MessageDefinition, arb_id: ArbitrationId) -> None: ) else: log.debug("Read motor status terminated, no missing nodes.") - return reported + finally: + can_messenger.remove_listener(_listener) + return reported async def get_tip_motor_enabled( diff --git a/hardware/opentrons_hardware/hardware_control/move_group_runner.py b/hardware/opentrons_hardware/hardware_control/move_group_runner.py index 8bec107549d..905da87a3ff 100644 --- a/hardware/opentrons_hardware/hardware_control/move_group_runner.py +++ b/hardware/opentrons_hardware/hardware_control/move_group_runner.py @@ -310,6 +310,7 @@ def _get_stepper_motor_message( return HomeRequest(payload=home_payload) elif step.move_type == MoveType.sensor: # stop_condition = step.stop_condition.value + assert step.sensor_id is not None stop_condition = MoveStopCondition.sync_line sensor_move_payload = AddSensorLinearMoveBasePayload( # need to create unique pressure and capacitive moves. S0 and S1 too? Check Ryan's work request_stop_condition=MoveStopConditionField(stop_condition), diff --git a/hardware/opentrons_hardware/hardware_control/tool_sensors.py b/hardware/opentrons_hardware/hardware_control/tool_sensors.py index 43fdaca5001..72332a8349f 100644 --- a/hardware/opentrons_hardware/hardware_control/tool_sensors.py +++ b/hardware/opentrons_hardware/hardware_control/tool_sensors.py @@ -86,6 +86,7 @@ def _build_pass_step_pressure( distance: Dict[NodeId, float], speed: Dict[NodeId, float], stop_condition: MoveStopCondition = MoveStopCondition.sync_line, + sensor_to_use: Optional[SensorId] = None, ) -> MoveGroupStep: pipette_nodes = [ i for i in movers if i in [NodeId.pipette_left, NodeId.pipette_right] @@ -174,86 +175,175 @@ async def run_sync_buffer_to_csv( threshold: float, head_node: NodeId, move_group: MoveGroupRunner, - log_file: str, - tool: PipetteProbeTarget, - sensor_id: SensorId, + log_files: Dict[SensorId, str], + tool: InstrumentProbeTarget, sensor_type: SensorType, output_file_heading: list[str], ) -> Dict[NodeId, MotorPositionStatus]: """Runs the sensor pass move group and creates a csv file with the results.""" sensor_metadata = [0, 0, mount_speed, plunger_speed, threshold] - sensor_capturer = LogListener( - mount=head_node, - data_file=log_file, - file_heading=output_file_heading, - sensor_metadata=sensor_metadata, - ) - async with sensor_capturer: - positions = await move_group.run(can_messenger=messenger) - messenger.add_listener(sensor_capturer, None) + positions = await move_group.run(can_messenger=messenger) + for sensor_id in log_files.keys(): + sensor_capturer = LogListener( + mount=head_node, + data_file=log_files[sensor_id], + file_heading=output_file_heading, + sensor_metadata=sensor_metadata, + ) + async with sensor_capturer: + messenger.add_listener(sensor_capturer, None) + await messenger.send( + node_id=tool, + message=SendAccumulatedPressureDataRequest( + payload=SendAccumulatedPressureDataPayload( + sensor_id=SensorIdField(sensor_id), + sensor_type=SensorTypeField(sensor_type), + ) + ), + ) + await asyncio.sleep(10) + messenger.remove_listener(sensor_capturer) await messenger.send( node_id=tool, - message=SendAccumulatedSensorDataRequest( - payload=SendAccumulatedSensorDataPayload( + message=BindSensorOutputRequest( + payload=BindSensorOutputRequestPayload( + sensor=SensorTypeField(sensor_type), sensor_id=SensorIdField(sensor_id), - sensor_type=SensorTypeField(sensor_type), + binding=SensorOutputBindingField(SensorOutputBinding.none), ) ), ) - await asyncio.sleep(10) - messenger.remove_listener(sensor_capturer) - await messenger.send( # redundant - node_id=tool, - message=BindSensorOutputRequest( - payload=BindSensorOutputRequestPayload( - sensor=SensorTypeField(sensor_type), - sensor_id=SensorIdField(sensor_id), - binding=SensorOutputBindingField(SensorOutputBinding.none), - ) - ), - ) return positions async def run_stream_output_to_csv( messenger: CanMessenger, sensor_driver: SensorDriver, - sensor: BaseSensorType, + sensors: Dict[SensorId, BaseSensorType], mount_speed: float, plunger_speed: float, threshold: float, head_node: NodeId, move_group: MoveGroupRunner, - log_file: str, + log_files: Dict[SensorId, str], output_file_heading: list[str], ) -> Dict[NodeId, MotorPositionStatus]: """Runs the sensor pass move group and creates a csv file with the results.""" sensor_metadata = [0, 0, mount_speed, plunger_speed, threshold] sensor_capturer = LogListener( mount=head_node, - data_file=log_file, + data_file=log_files[ + next(iter(log_files)) + ], # hardcode to the first file, need to think more on this file_heading=output_file_heading, sensor_metadata=sensor_metadata, ) - binding = [ - SensorOutputBinding.sync, - SensorOutputBinding.report, - ] - - async with sensor_driver.bind_output( - messenger, sensor, binding - ): - messenger.add_listener( - sensor_capturer, None + binding = [SensorOutputBinding.sync, SensorOutputBinding.report] + binding_field = SensorOutputBindingField.from_flags(binding) + for sensor_id in sensors.keys(): + sensor_info = sensors[sensor_id].sensor + await messenger.send( + node_id=sensor_info.node_id, + message=BindSensorOutputRequest( + payload=BindSensorOutputRequestPayload( + sensor=SensorTypeField(sensor_info.sensor_type), + sensor_id=SensorIdField(sensor_info.sensor_id), + binding=binding_field, + ) + ), ) - async with sensor_capturer: - positions = await move_group.run(can_messenger=messenger) - messenger.remove_listener(sensor_capturer) + messenger.add_listener(sensor_capturer, None) + async with sensor_capturer: + positions = await move_group.run(can_messenger=messenger) + messenger.remove_listener(sensor_capturer) + for sensor_id in sensors.keys(): + sensor_info = sensors[sensor_id].sensor + await messenger.send( + node_id=sensor_info.node_id, + message=BindSensorOutputRequest( + payload=BindSensorOutputRequestPayload( + sensor=SensorTypeField(sensor_info.sensor_type), + sensor_id=SensorIdField(sensor_info.sensor_id), + binding=SensorOutputBindingField(SensorOutputBinding.none), + ) + ), + ) return positions +async def _setup_pressure_sensors( + messenger: CanMessenger, + sensor_id: SensorId, + tool: PipetteProbeTarget, + num_baseline_reads: int, + threshold_fixed_point: float, + sensor_driver: SensorDriver, + auto_zero_sensor: bool, +) -> Dict[SensorId, PressureSensor]: + sensors: List[SensorId] = [] + result: Dict[SensorId, PressureSensor] = {} + if sensor_id == SensorId.BOTH: + sensors.append(SensorId.S0) + sensors.append(SensorId.S1) + else: + sensors.append(sensor_id) + + for sensor in sensors: + pressure_sensor = PressureSensor.build( + sensor_id=sensor, + node_id=tool, + stop_threshold=threshold_fixed_point, + ) + + if auto_zero_sensor: + pressure_baseline = await sensor_driver.get_baseline( + messenger, pressure_sensor, num_baseline_reads + ) + LOG.debug(f"found baseline pressure: {pressure_baseline} pascals") + + await sensor_driver.send_stop_threshold(messenger, pressure_sensor) + result[sensor] = pressure_sensor + return result + + +async def _run_with_binding( + messenger: CanMessenger, + pressure_sensors: Dict[SensorId, PressureSensor], + sensor_runner: MoveGroupRunner, + binding: List[SensorOutputBinding], +) -> Dict[NodeId, MotorPositionStatus]: + binding_field = SensorOutputBindingField.from_flags(binding) + for sensor_id in pressure_sensors.keys(): + sensor_info = pressure_sensors[sensor_id].sensor + await messenger.send( + node_id=sensor_info.node_id, + message=BindSensorOutputRequest( + payload=BindSensorOutputRequestPayload( + sensor=SensorTypeField(sensor_info.sensor_type), + sensor_id=SensorIdField(sensor_info.sensor_id), + binding=binding_field, + ) + ), + ) + + result = await sensor_runner.run(can_messenger=messenger) + for sensor_id in pressure_sensors.keys(): + sensor_info = pressure_sensors[sensor_id].sensor + await messenger.send( + node_id=sensor_info.node_id, + message=BindSensorOutputRequest( + payload=BindSensorOutputRequestPayload( + sensor=SensorTypeField(sensor_info.sensor_type), + sensor_id=SensorIdField(sensor_info.sensor_id), + binding=SensorOutputBindingField(SensorOutputBinding.none), + ) + ), + ) + return result + + async def liquid_probe( messenger: CanMessenger, tool: PipetteProbeTarget, @@ -265,48 +355,47 @@ async def liquid_probe( csv_output: bool = False, sync_buffer_output: bool = False, can_bus_only_output: bool = False, - data_file: Optional[str] = None, + data_files: Optional[Dict[SensorId, str]] = None, auto_zero_sensor: bool = True, num_baseline_reads: int = 10, sensor_id: SensorId = SensorId.S0, ) -> Dict[NodeId, MotorPositionStatus]: """Move the mount and pipette simultaneously while reading from the pressure sensor.""" + log_files: Dict[SensorId, str] = {} if not data_files else data_files sensor_driver = SensorDriver() threshold_fixed_point = threshold_pascals * sensor_fixed_point_conversion - pressure_sensor = PressureSensor.build( - sensor_id=sensor_id, - node_id=tool, - stop_threshold=threshold_fixed_point, + pressure_sensors = await _setup_pressure_sensors( + messenger, + sensor_id, + tool, + num_baseline_reads, + threshold_fixed_point, + sensor_driver, + auto_zero_sensor, ) - if auto_zero_sensor: - pressure_baseline = await sensor_driver.get_baseline( - messenger, pressure_sensor, num_baseline_reads - ) - LOG.debug(f"found baseline pressure: {pressure_baseline} pascals") - - await sensor_driver.send_stop_threshold(messenger, pressure_sensor) + sensor_driver.send_stop_threshold(messenger, pressure_sensor) sensor_group = _build_pass_step_pressure( movers=[head_node, tool], distance={head_node: max_z_distance, tool: max_z_distance}, speed={head_node: mount_speed, tool: plunger_speed}, stop_condition=MoveStopCondition.sync_line, + sensor_id=sensor_id, ) sensor_runner = MoveGroupRunner(move_groups=[[sensor_group]]) - log_file: str = "/data/pressure_sensor_data.csv" if not data_file else data_file if csv_output: return await run_stream_output_to_csv( messenger, sensor_driver, - pressure_sensor, + pressure_sensors, mount_speed, plunger_speed, threshold_pascals, head_node, sensor_runner, - log_file, + log_files, pressure_output_file_heading, ) elif sync_buffer_output: @@ -317,31 +406,21 @@ async def liquid_probe( threshold_pascals, head_node, sensor_runner, - log_file, + log_files, tool=tool, - sensor_id=sensor_id, sensor_type=SensorType.pressure, output_file_heading=pressure_output_file_heading, ) elif can_bus_only_output: - async with sensor_driver.bind_output( - messenger, - pressure_sensor, - [ - SensorOutputBinding.sync, - SensorOutputBinding.report, - ], - ): - return await sensor_runner.run(can_messenger=messenger) + binding = [SensorOutputBinding.sync, SensorOutputBinding.report] + return await _run_with_binding( + messenger, pressure_sensors, sensor_runner, binding + ) else: # none - async with sensor_driver.bind_output( - messenger, - pressure_sensor, - [ - SensorOutputBinding.sync, - ], - ): - return await sensor_runner.run(can_messenger=messenger) + binding = [SensorOutputBinding.sync] + return await _run_with_binding( + messenger, pressure_sensors, sensor_runner, binding + ) async def check_overpressure( diff --git a/hardware/tests/opentrons_hardware/hardware_control/test_tool_sensors.py b/hardware/tests/opentrons_hardware/hardware_control/test_tool_sensors.py index d9306076d7b..1881db4a57d 100644 --- a/hardware/tests/opentrons_hardware/hardware_control/test_tool_sensors.py +++ b/hardware/tests/opentrons_hardware/hardware_control/test_tool_sensors.py @@ -50,7 +50,7 @@ SensorOutputBinding, ) from opentrons_hardware.sensors.scheduler import SensorScheduler -from opentrons_hardware.sensors.sensor_driver import LogListener, SensorDriver +from opentrons_hardware.sensors.sensor_driver import SensorDriver from opentrons_hardware.sensors.types import SensorDataType from opentrons_hardware.sensors.sensor_types import SensorInformation from opentrons_hardware.sensors.utils import SensorThresholdInformation @@ -193,35 +193,6 @@ def move_responder( data=SensorDataType.build(threshold_pascals * 65536, sensor_info.sensor_type), mode=SensorThresholdMode.absolute, ) - mock_bind_output.assert_called_once() - assert mock_bind_output.call_args_list[0][0][3] == [SensorOutputBinding.sync] - - with patch( - "opentrons_hardware.hardware_control.tool_sensors", LogListener - ) as mock_log: - - mock_log.__aenter__ = AsyncMock(return_value=mock_log) # type: ignore - mock_log.__aexit__ = AsyncMock(return_value=None) # type: ignore - - await liquid_probe( - messenger=mock_messenger, - tool=target_node, - head_node=motor_node, - max_z_distance=40, - mount_speed=10, - plunger_speed=8, - threshold_pascals=threshold_pascals, - csv_output=False, - sync_buffer_output=False, - can_bus_only_output=False, - auto_zero_sensor=True, - num_baseline_reads=8, - sensor_id=SensorId.S0, - ) - mock_bind_output.assert_called() - assert mock_bind_output.call_args_list[1][0][3] == [ - SensorOutputBinding.sync, - ] @pytest.mark.parametrize( diff --git a/labware-designer/webpack.config.js b/labware-designer/webpack.config.js deleted file mode 100644 index aec3b7cc0cb..00000000000 --- a/labware-designer/webpack.config.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict' - -const path = require('path') -const webpackMerge = require('webpack-merge') -const HtmlWebpackPlugin = require('html-webpack-plugin') -const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin') - -const { baseConfig } = require('@opentrons/webpack-config') -const { productName: title, description, author } = require('./package.json') - -const JS_ENTRY = path.join(__dirname, 'src/index.tsx') -const HTML_ENTRY = path.join(__dirname, 'src/index.hbs') -const OUTPUT_PATH = path.join(__dirname, 'dist') - -module.exports = webpackMerge(baseConfig, { - entry: [JS_ENTRY], - - output: { - path: OUTPUT_PATH, - }, - - plugins: [ - new HtmlWebpackPlugin({ title, description, author, template: HTML_ENTRY }), - new ScriptExtHtmlWebpackPlugin({ defaultAttribute: 'defer' }), - ], -}) diff --git a/labware-library/Makefile b/labware-library/Makefile index ab92ed2b1a5..92fe4785cda 100644 --- a/labware-library/Makefile +++ b/labware-library/Makefile @@ -44,7 +44,7 @@ serve: all test-e2e: concurrently --no-color --kill-others --success first --names "labware-library-server,labware-library-tests" \ "$(MAKE) dev CYPRESS=1 GTM_ID=''" \ - "wait-on http://localhost:5173/ && echo \"Running cypress at $(date)\" && cypress run --browser chrome --headless --record false" + "wait-on http://localhost:5179/ && echo \"Running cypress at $(date)\" && cypress run --browser chrome --headless --record false" # unit tests .PHONY: test diff --git a/labware-library/cypress.config.js b/labware-library/cypress.config.js new file mode 100644 index 00000000000..e1871656f84 --- /dev/null +++ b/labware-library/cypress.config.js @@ -0,0 +1,13 @@ +const { defineConfig } = require('cypress') + +module.exports = defineConfig({ + video: false, + e2e: { + // We've imported your old cypress plugins here. + // You may want to clean this up later by importing these. + setupNodeEvents(on, config) { + return require('./cypress/plugins/index.js')(on, config) + }, + baseUrl: 'http://localhost:5179', + }, +}) diff --git a/labware-library/cypress.json b/labware-library/cypress.json deleted file mode 100644 index 68db341a5ba..00000000000 --- a/labware-library/cypress.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "baseUrl": "http://localhost:5173", - "video": false -} diff --git a/labware-library/cypress/integration/home.spec.js b/labware-library/cypress/e2e/home.cy.js similarity index 100% rename from labware-library/cypress/integration/home.spec.js rename to labware-library/cypress/e2e/home.cy.js diff --git a/labware-library/cypress/integration/labware-creator/create.spec.js b/labware-library/cypress/e2e/labware-creator/create.cy.js similarity index 98% rename from labware-library/cypress/integration/labware-creator/create.spec.js rename to labware-library/cypress/e2e/labware-creator/create.cy.js index c0a667be233..3c2999653d0 100644 --- a/labware-library/cypress/integration/labware-creator/create.spec.js +++ b/labware-library/cypress/e2e/labware-creator/create.cy.js @@ -3,7 +3,7 @@ // { force: true } context('The Labware Creator Landing Page', () => { - before(() => { + beforeEach(() => { cy.visit('/create') cy.viewport('macbook-15') cy.contains('NO').click({ force: true }) diff --git a/labware-library/cypress/integration/labware-creator/customTubeRack.spec.js b/labware-library/cypress/e2e/labware-creator/customTubeRack.cy.js similarity index 88% rename from labware-library/cypress/integration/labware-creator/customTubeRack.spec.js rename to labware-library/cypress/e2e/labware-creator/customTubeRack.cy.js index e9f829a438f..7d864ccb711 100644 --- a/labware-library/cypress/integration/labware-creator/customTubeRack.spec.js +++ b/labware-library/cypress/e2e/labware-creator/customTubeRack.cy.js @@ -11,13 +11,10 @@ context('Tubes and Rack', () => { }) describe('Custom 6 x 4 tube rack', () => { - it('should show analytics opt-in', () => { + it('should create a custom tuberack', () => { cy.contains('Share sessions with the Opentrons Product Team?') cy.contains('NO').click({ force: true }) - }) - it('should allow user to select custom tube rack', () => { - // TODO(IL, 2021-05-15): give Dropdown component semantic selectors for E2E cy.get('label') .contains('What type of labware are you creating?') .children() @@ -25,7 +22,6 @@ context('Tubes and Rack', () => { .trigger('mousedown') cy.get('*[class^="_option_label"]').contains('Tubes + Tube Rack').click() - // TODO(IL, 2021-05-15): give Dropdown component semantic selectors for E2E cy.get('label') .contains('Which tube rack?') .children() @@ -36,13 +32,11 @@ context('Tubes and Rack', () => { .click() cy.contains('start creating labware').click({ force: true }) - }) - it('does not have a preview image', () => { + // no preview image yet cy.contains('Add missing info to see labware preview').should('exist') - }) - it('tests regularity', () => { + // regularity cy.get("input[name='homogeneousWells'][value='false']").check({ force: true, }) @@ -58,9 +52,8 @@ context('Tubes and Rack', () => { cy.get("input[name='footprintXDimension']").type('128').blur() cy.get("input[name='footprintYDimension']").clear().type('86').blur() - }) - it('tests height', () => { + // height cy.get("input[name='labwareZDimension']").type('150').blur() cy.contains('This labware may be too tall').should('exist') cy.get("input[name='labwareZDimension']").clear().type('200').blur() @@ -72,9 +65,8 @@ context('Tubes and Rack', () => { cy.contains( 'Your labware is not compatible with the Labware Creator' ).should('not.exist') - }) - it('tests grid', () => { + // grid cy.get("input[name='gridRows']").type('6').blur() cy.get("input[name='gridColumns']").type('4').blur() @@ -84,16 +76,14 @@ context('Tubes and Rack', () => { cy.get("input[name='regularColumnSpacing'][value='true']").check({ force: true, }) - }) - it('tests volume', () => { + // volume cy.get("input[name='wellVolume']").focus().blur() cy.contains('Volume is a required field').should('exist') cy.get("input[name='wellVolume']").type('1500').blur() cy.contains('Volume is a required field').should('not.exist') - }) - it('tests rectangular wells', () => { + // rectangular wells cy.get("input[name='wellShape'][value='rectangular']").check({ force: true, }) @@ -108,9 +98,8 @@ context('Tubes and Rack', () => { cy.contains('Tube Y is a required field').should('exist') cy.get("input[name='wellYDimension']").type('10').blur() cy.contains('Tube Y is a required field').should('not.exist') - }) - it('tests circular wells', () => { + // circular wells cy.get("input[name='wellShape'][value='circular']").check({ force: true, }) @@ -121,9 +110,8 @@ context('Tubes and Rack', () => { cy.contains('Diameter is a required field').should('exist') cy.get("input[name='wellDiameter']").type('12').blur() cy.contains('Diameter is a required field').should('not.exist') - }) - it('tests well bottom shape and depth', () => { + // well bottom shape and depth cy.get("input[name='wellBottomShape'][value='flat']").check({ force: true, }) @@ -146,20 +134,17 @@ context('Tubes and Rack', () => { cy.contains('Depth is a required field').should('exist') cy.get("input[name='wellDepth']").type('100').blur() cy.contains('Depth is a required field').should('not.exist') - }) - it('tests offset', () => { + // offset cy.get("input[name='gridSpacingX']").type('18').blur() cy.get("input[name='gridSpacingY']").type('14').blur() cy.get("input[name='gridOffsetX']").type('15').blur() cy.get("input[name='gridOffsetY']").type('8').blur() - }) - it('does has a preview image', () => { + // verify preview image cy.contains('Add missing info to see labware preview').should('not.exist') - }) - it('tests the file export', () => { + // test file export // Try with missing fields cy.get('button[class*="_export_button_"]').click({ force: true }) cy.contains( @@ -180,9 +165,8 @@ context('Tubes and Rack', () => { cy.get("input[placeholder='somerackbrand_24_tuberack_1500ul']").should( 'exist' ) - }) - it('should export a file matching the fixture', () => { + // now try again with all fields inputed cy.fixture(expectedExportFixture).then(expectedExportLabwareDef => { cy.get('button').contains('EXPORT FILE').click() diff --git a/labware-library/cypress/integration/labware-creator/fileImport.spec.js b/labware-library/cypress/e2e/labware-creator/fileImport.cy.js similarity index 73% rename from labware-library/cypress/integration/labware-creator/fileImport.spec.js rename to labware-library/cypress/e2e/labware-creator/fileImport.cy.js index 97650526e22..ec0094b3806 100644 --- a/labware-library/cypress/integration/labware-creator/fileImport.spec.js +++ b/labware-library/cypress/e2e/labware-creator/fileImport.cy.js @@ -2,14 +2,15 @@ import { expectDeepEqual } from '@opentrons/shared-data/js/cypressUtils' const importedLabwareFile = 'TestLabwareDefinition.json' -context('File Import', () => { +describe('File Import', () => { before(() => { cy.visit('/create') cy.viewport('macbook-15') cy.contains('NO').click({ force: true }) }) - it('drags in a file', () => { + it('tests the file import flow', () => { + // import file cy.fixture(importedLabwareFile, 'utf8').then(fileJson => { const fileContent = JSON.stringify(fileJson) cy.get('[class*="file_drop"]').first().upload( @@ -22,71 +23,47 @@ context('File Import', () => { { subjectType: 'drag-n-drop', force: true } ) }) - }) - it('does has a preview image', () => { + // verify preview image cy.contains('Add missing info to see labware preview').should('not.exist') - }) - - it('tests regularity', () => { + // verify regularity cy.get("input[name='homogeneousWells'][value='true']").should('be.checked') - }) - - it('tests footprint', () => { + // verify footprint cy.get("input[name='footprintXDimension'][value='127']").should('exist') cy.get("input[name='footprintYDimension'][value='85']").should('exist') - }) - - it('tests height', () => { + // verify height cy.get("input[name='labwareZDimension'][value='5']").should('exist') - }) - - describe('Grid tests', () => { - it('tests number of rows', () => { - cy.get("input[name='gridRows'][value='3']").should('exist') - }) - - it('tests are all of your rows evenly spaced', () => { - cy.get("input[name='regularRowSpacing'][value='true']").should('exist') - }) - - it('tests number of columns', () => { - cy.get("input[name='gridColumns'][value='5']").should('exist') - }) - - it('tests are all of your columns evenly spaced', () => { - cy.get("input[name='regularColumnSpacing'][value='true']").should('exist') - }) - }) - - it('tests volume', () => { + // verify number of rows + cy.get("input[name='gridRows'][value='3']").should('exist') + // verify rows are evenly spaced + cy.get("input[name='regularRowSpacing'][value='true']").should('exist') + // verify number of columns + cy.get("input[name='gridColumns'][value='5']").should('exist') + // verify columns are evenly spaced + cy.get("input[name='regularColumnSpacing'][value='true']").should('exist') + + // verify volume cy.get("input[name='wellVolume'][value='5']").should('exist') - }) - - it('tests well shape', () => { + // verify well shape cy.get("input[name='wellShape'][value='circular']").should('exist') cy.get("input[name='wellDiameter'][value='5']").should('exist') - }) - it('tests well bottom shape and depth', () => { + // verify well bottom and depth cy.get("input[name='wellBottomShape'][value='flat']").should('exist') cy.get("img[src*='_flat.']").should('exist') cy.get("img[src*='_round.']").should('not.exist') cy.get("img[src*='_v.']").should('not.exist') cy.get("input[name='wellDepth'][value='5']").should('exist') - }) - it('tests well spacing', () => { + // verify grid spacing cy.get("input[name='gridSpacingX'][value='25']").should('exist') cy.get("input[name='gridSpacingY'][value='25']").should('exist') - }) - it('tests grid offset', () => { + // verify grid offset cy.get("input[name='gridOffsetX'][value='10']").should('exist') cy.get("input[name='gridOffsetY'][value='10']").should('exist') - }) - it('tests the file export', () => { + // go through file export // Brand info cy.get("input[name='brand'][value='TestPro']").should('exist') cy.get("input[name='brandId'][value='001']").should('exist') diff --git a/labware-library/cypress/e2e/labware-creator/reservoir.cy.js b/labware-library/cypress/e2e/labware-creator/reservoir.cy.js new file mode 100644 index 00000000000..c25dc51497e --- /dev/null +++ b/labware-library/cypress/e2e/labware-creator/reservoir.cy.js @@ -0,0 +1,211 @@ +// Scrolling seems wonky, so I disabled checking to see if +// an element is in view before clicking or checking with +// { force: true } + +context('Reservoirs', () => { + before(() => { + cy.visit('/create') + cy.viewport('macbook-15') + cy.contains('NO').click({ force: true }) + }) + + describe('Reservoir', () => { + before(() => { + cy.contains('What type of labware are you creating?') + .children() + .first() + .trigger('mousedown') + cy.get('*[class^="_option_label"]').contains('Reservoir').click() + cy.contains('Reservoir').click({ force: true }) + cy.contains('start creating labware').click({ force: true }) + }) + + it('should create a resevoir', () => { + cy.contains('Add missing info to see labware preview').should('exist') + + // verify regularity + cy.get("input[name='homogeneousWells'][value='false']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('exist') + cy.get("input[name='homogeneousWells'][value='true']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('not.exist') + + // verify footprint + + cy.get("input[name='footprintXDimension']").type('150').blur() + cy.contains( + 'Your labware is too large to fit in a single slot properly. Please fill out this form to request a custom labware definition.' + ).should('exist') + cy.get("input[name='footprintXDimension']").clear().type('127').blur() + cy.contains( + 'Your labware is too large to fit in a single slot properly. Please fill out this form to request a custom labware definition.' + ).should('not.exist') + cy.get("input[name='footprintYDimension']").type('150').blur() + cy.contains( + 'Your labware is too large to fit in a single slot properly. Please fill out this form to request a custom labware definition.' + ).should('exist') + cy.get("input[name='footprintYDimension']").clear().type('85').blur() + cy.contains( + 'Your labware is too large to fit in a single slot properly. Please fill out this form to request a custom labware definition.' + ).should('not.exist') + + // verify height + + cy.get("input[name='labwareZDimension']").type('150').blur() + cy.contains('This labware may be too tall').should('exist') + cy.get("input[name='labwareZDimension']").clear().type('200').blur() + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('exist') + cy.get("input[name='labwareZDimension']").clear().type('75').blur() + cy.contains('This labware may be too tall').should('not.exist') + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('not.exist') + + // verify rows + cy.get("input[name='gridRows']").focus().blur() + cy.contains('Number of rows is a required field').should('exist') + cy.get("input[name='gridRows']").type('1').blur() + cy.contains('Number of rows is a required field').should('not.exist') + + // should not ask if all of your rows evenly spaced, since we only have one row + + cy.get("input[name='regularRowSpacing'][value='false']").should( + 'not.exist' + ) + + // verify number of columns + + cy.get("input[name='gridColumns']").focus().blur() + cy.contains('Number of columns is a required field').should('exist') + cy.get("input[name='gridColumns']").type('10').blur() + cy.contains('Number of columns is a required field').should('not.exist') + + // verify columns are evenly spaced + + cy.get("input[name='regularColumnSpacing'][value='false']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('exist') + cy.get("input[name='regularColumnSpacing'][value='true']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('not.exist') + + // verify volume + + cy.get("input[name='wellVolume']").focus().blur() + cy.contains('Volume is a required field').should('exist') + cy.get("input[name='wellVolume']").type('250').blur() + cy.contains('Volume is a required field').should('not.exist') + + // verify circular wells + cy.get("input[name='wellShape'][value='circular']").check({ + force: true, + }) + cy.get("input[name='wellDiameter']").should('exist') + cy.get("input[name='wellXDimension']").should('not.exist') + cy.get("input[name='wellYDimension']").should('not.exist') + cy.get("input[name='wellDiameter']").focus().blur() + cy.contains('Diameter is a required field').should('exist') + cy.get("input[name='wellDiameter']").type('10').blur() + cy.contains('Diameter is a required field').should('not.exist') + + // verify rectangular wells + + cy.get("input[name='wellShape'][value='rectangular']").check({ + force: true, + }) + cy.get("input[name='wellDiameter']").should('not.exist') + cy.get("input[name='wellXDimension']").should('exist') + cy.get("input[name='wellYDimension']").should('exist') + cy.get("input[name='wellXDimension']").focus().blur() + cy.contains('Well X is a required field').should('exist') + cy.get("input[name='wellXDimension']").type('8').blur() + cy.contains('Well X is a required field').should('not.exist') + cy.get("input[name='wellYDimension']").focus().blur() + cy.contains('Well Y is a required field').should('exist') + cy.get("input[name='wellYDimension']").type('60').blur() + cy.contains('Well Y is a required field').should('not.exist') + + // verify well bottom shape and depth + cy.get("input[name='wellBottomShape'][value='flat']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('exist') + cy.get("img[src*='_round.']").should('not.exist') + cy.get("img[src*='_v.']").should('not.exist') + cy.get("input[name='wellBottomShape'][value='u']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('not.exist') + cy.get("img[src*='_round.']").should('exist') + cy.get("img[src*='_v.']").should('not.exist') + cy.get("input[name='wellBottomShape'][value='v']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('not.exist') + cy.get("img[src*='_round.']").should('not.exist') + cy.get("img[src*='_v.']").should('exist') + cy.get("input[name='wellDepth']").focus().blur() + cy.contains('Depth is a required field').should('exist') + cy.get("input[name='wellDepth']").type('70').blur() + cy.contains('Depth is a required field').should('not.exist') + + // verify grid spacing + + cy.get("input[name='gridSpacingX']").focus().blur() + cy.contains('X Spacing (Xs) is a required field').should('exist') + cy.get("input[name='gridSpacingX']").type('12').blur() + cy.contains('X Spacing (Xs) is a required field').should('not.exist') + + // verify grid offset + cy.get("input[name='gridOffsetX']").focus().blur() + cy.contains('X Offset (Xo) is a required field').should('exist') + cy.get("input[name='gridOffsetX']").type('10').blur() + cy.contains('X Offset (Xo) is a required field').should('not.exist') + cy.get("input[name='gridOffsetY']").focus().blur() + cy.contains('Y Offset (Yo) is a required field').should('exist') + cy.get("input[name='gridOffsetY']").type('45').blur() + cy.contains('Y Offset (Yo) is a required field').should('not.exist') + + cy.contains('Add missing info to see labware preview').should('not.exist') + + // verify file export + // Try with missing fields + cy.get('button[class*="_export_button_"]').click({ force: true }) + cy.contains( + 'Please resolve all invalid fields in order to export the labware definition' + ).should('exist') + cy.contains('close').click({ force: true }) + + // Brand info + cy.contains('Brand is a required field').should('exist') + cy.get("input[name='brand']").type('TestPro') + cy.contains('Brand is a required field').should('not.exist') + cy.get("input[name='brandId']").type('001') + + // File info + cy.get("input[placeholder='TestPro 10 Reservoir 250 µL']").should('exist') + cy.get("input[placeholder='testpro_10_reservoir_250ul']").should('exist') + + // All fields present + cy.get('button[class*="_export_button_"]').click({ force: true }) + cy.contains( + 'Please resolve all invalid fields in order to export the labware definition' + ).should('not.exist') + }) + }) +}) diff --git a/labware-library/cypress/integration/labware-creator/tipRack.spec.js b/labware-library/cypress/e2e/labware-creator/tipRack.cy.js similarity index 91% rename from labware-library/cypress/integration/labware-creator/tipRack.spec.js rename to labware-library/cypress/e2e/labware-creator/tipRack.cy.js index 188ec69f6eb..4963f493b64 100644 --- a/labware-library/cypress/integration/labware-creator/tipRack.spec.js +++ b/labware-library/cypress/e2e/labware-creator/tipRack.cy.js @@ -9,7 +9,8 @@ describe('Create a Tip Rack', () => { cy.viewport('macbook-15') cy.contains('NO').click({ force: true }) }) - it('Tip Rack Selection from drop down', () => { + it('Should create a tip rack', () => { + // Tip Rack Selection from drop down cy.get('label') .contains('What type of labware are you creating?') .children() @@ -17,9 +18,8 @@ describe('Create a Tip Rack', () => { .trigger('mousedown') cy.get('*[class^="_option_label"]').contains('Tip Rack').click() cy.get('button').contains('start creating labware').click({ force: true }) - }) - it('Custom Tip Racks Are Not Recommended', () => { + // Custom Tip Racks Are Not Recommended cy.get('#CustomTiprackWarning p') .first() .contains( @@ -32,9 +32,8 @@ describe('Create a Tip Rack', () => { 'Third party tips can fit, but not necessarily with a tight seal. You risk tips falling off mid-run as well as pipetting inaccuracy. They may also be more likely to bend or break.' ) .should('exist') - }) - it('Verify Hand-Placed Tip Fit section', () => { + // Verify Hand-Placed Tip Fit section cy.get('#HandPlacedTipFit h2') .contains('Hand-Placed Tip Fit') .should('exist') @@ -84,9 +83,8 @@ describe('Create a Tip Rack', () => { 'If your tip seems to fit when placed by hand it may work on the OT-2. Proceed through the form to generate a definition. Once you have a definition you can check performance on the robot.' ) .should('exist') - }) - it('Verify Total Footprint section', () => { + // Verify Total Footprint section cy.get('#Footprint h2').contains('Total Footprint').should('exist') // verify the copy changes in the Total Footprint section @@ -110,9 +108,7 @@ describe('Create a Tip Rack', () => { // Enter the length and width for the Footprint cy.get('input[name="footprintXDimension"]').clear().type('127') cy.get('input[name="footprintYDimension"]').clear().type('85') - }) - it('Verify errors in Total Footprint section', () => { // verify that length displays error for smaller value cy.get('input[name="footprintXDimension"]').clear().type('20') cy.get('#Footprint span') @@ -148,9 +144,8 @@ describe('Create a Tip Rack', () => { // entering the valid values for footprint cy.get('input[name="footprintXDimension"]').clear().type('127') cy.get('input[name="footprintYDimension"]').clear().type('85') - }) - it('Verify copy error in Total Height section', () => { + // Verify copy error in Total Height section cy.get('#Height h2').contains('Total Height').should('exist') cy.get('#Height p') .first() @@ -166,18 +161,16 @@ describe('Create a Tip Rack', () => { .should('exist') cy.get('img[alt="plate or reservoir height"]').should('exist') cy.get('input[name="labwareZDimension"]').clear().type('24') - }) - it('verify the Tip Length section', () => { + // Verify the Tip Length section cy.get('#WellBottomAndDepth h2').contains('Tip Length').should('exist') cy.get('#WellBottomAndDepth p') .contains('Reference the top of the tip to the bottom of the tip.') .should('exist') cy.get('img[alt="tip length"]').should('exist') cy.get('input[name="wellDepth"]').clear().type('12') - }) - it('verify the Grid section', () => { + // Verify the Grid section cy.get('#Grid h2').contains('Grid').should('exist') cy.get('#Grid p') .contains( @@ -189,26 +182,23 @@ describe('Create a Tip Rack', () => { cy.get('input[name="regularRowSpacing"]').first().click({ force: true }) cy.get('input[name="gridColumns"]').clear().type('5') cy.get('input[name="regularColumnSpacing"]').first().click({ force: true }) - }) - it('Verify copy change for volume', () => { + // Verify copy change for volume cy.get('#Volume h2').contains('Volume').should('exist') cy.get('#Volume p') .contains('Total maximum volume of each tip.') .should('exist') cy.get('input[name="wellVolume"]').clear().type('20') - }) - it('Verify the tip diameter of the tip', () => { + // Verify the tip diameter of the tip cy.get('#TipDiameter h2').contains('Tip Diameter').should('exist') cy.get('#TipDiameter p') .contains('Reference the inside of the tip.') .should('exist') cy.get('img[alt="circular well diameter"]').should('exist') cy.get('input[name="wellDiameter"]').clear().type('10') - }) - it('Verify the Tip Spacing section', () => { + // Verify the Tip Spacing section cy.get('#WellSpacing h2').contains('Tip Spacing').should('exist') cy.get('#WellSpacing p') .contains('Spacing is between the center of tips.') @@ -222,9 +212,8 @@ describe('Create a Tip Rack', () => { cy.get('img[alt="circular well spacing"]').should('exist') cy.get('input[name="gridSpacingX"]').clear().type('15') cy.get('input[name="gridSpacingY"]').clear().type('15') - }) - it('Verify the Grid Offset section', () => { + // Verify the Grid Offset section cy.get('#GridOffset h2').contains('Grid Offset').should('exist') cy.get('#GridOffset p') .contains( @@ -241,25 +230,22 @@ describe('Create a Tip Rack', () => { cy.get('img[alt="circular well offset"]').should('exist') cy.get('input[name="gridOffsetX"]').clear().type('10') cy.get('input[name="gridOffsetY"]').clear().type('10') - }) - it('Verify the Description section', () => { + // Verify the Description section cy.get('#Description h2').contains('Description').should('exist') cy.get('input[name="brand"]').clear().type('Brand Chalu') cy.get('input[name="brandId"]') .clear() .type('abcd12345!@#$%,efghij6789^&*()') - }) - it('Verify the File section and enter the file name', () => { + // Verify the File section and enter the file name cy.get('#File h2').contains('File').should('exist') cy.get('input[name="displayName"]') .clear() .type('Brand Chalu 1 Tip Rack 20ul') cy.get('input[name="loadName"]').clear().type('generic_1_tiprack_20ul') - }) - it('Verify the exported file to the fixture', () => { + // Verify the exported file to the fixture cy.get('button').contains('EXPORT FILE').click() cy.fixture(expectedExportFixture).then(expectedExportLabwareDef => { @@ -277,8 +263,7 @@ describe('Create a Tip Rack', () => { cy.window() .its('__lastSavedFileName__') .should('equal', `generic_1_tiprack_20ul.json`) - }) - it('verify the too big, too small error', () => { + // 'verify the too big, too small error cy.get('input[name="gridOffsetY"]').clear().type('24') cy.get('#CheckYourWork span') .contains( diff --git a/labware-library/cypress/e2e/labware-creator/tubesBlock.cy.js b/labware-library/cypress/e2e/labware-creator/tubesBlock.cy.js new file mode 100644 index 00000000000..27b653e92a3 --- /dev/null +++ b/labware-library/cypress/e2e/labware-creator/tubesBlock.cy.js @@ -0,0 +1,591 @@ +// Scrolling seems wonky, so I disabled checking to see if +// an element is in view before clicking or checking with +// { force: true } + +context('Tubes and Block', () => { + beforeEach(() => { + cy.visit('/create') + cy.viewport('macbook-15') + cy.contains('NO').click({ force: true }) + + cy.get('label') + .contains('What type of labware are you creating?') + .children() + .first() + .trigger('mousedown') + cy.get('*[class^="_option_label"]') + .contains('Tubes / Plates + Opentrons Aluminum Block') + .click() + + cy.get('label') + .contains('Which aluminum block?') + .children() + .first() + .trigger('mousedown') + cy.get('*[class^="_option_label"]').contains('96 well').click() + + cy.get('label') + .contains('What labware is on top of your aluminum block?') + .children() + .first() + .trigger('mousedown') + cy.get('*[class^="_option_label"]') + .contains(/^Tubes$/) + .click() + + cy.contains('start creating labware').click({ force: true }) + }) + describe('96 Well', () => { + describe('Tubes', () => { + describe('Well shape tests', () => { + it('tests circular wells', () => { + cy.get("input[name='wellShape'][value='circular']").check({ + force: true, + }) + cy.get("input[name='wellDiameter']").should('exist') + cy.get("input[name='wellXDimension']").should('not.exist') + cy.get("input[name='wellYDimension']").should('not.exist') + cy.get("input[name='wellDiameter']").focus().blur() + cy.contains('Diameter is a required field').should('exist') + cy.get("input[name='wellDiameter']").type('10').blur() + cy.contains('Diameter is a required field').should('not.exist') + }) + + it('tests the whole form and file export', () => { + cy.contains('Add missing info to see labware preview').should('exist') + + // verify regularity + + cy.get("input[name='homogeneousWells'][value='false']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('exist') + cy.get("input[name='homogeneousWells'][value='true']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('not.exist') + + // verify height + cy.get("input[name='labwareZDimension']").type('150').blur() + cy.contains('This labware may be too tall').should('exist') + cy.get("input[name='labwareZDimension']").clear().type('200').blur() + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('exist') + cy.get("input[name='labwareZDimension']").clear().type('75').blur() + cy.contains('This labware may be too tall').should('not.exist') + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('not.exist') + + // verify volume + + cy.get("input[name='wellVolume']").focus().blur() + cy.contains('Volume is a required field').should('exist') + cy.get("input[name='wellVolume']").type('10').blur() + cy.contains('Volume is a required field').should('not.exist') + + cy.get("input[name='wellShape'][value='rectangular']").check({ + force: true, + }) + cy.get("input[name='wellDiameter']").should('not.exist') + cy.get("input[name='wellXDimension']").should('exist') + cy.get("input[name='wellYDimension']").should('exist') + cy.get("input[name='wellXDimension']").focus().blur() + cy.contains('Tube X is a required field').should('exist') + cy.get("input[name='wellXDimension']").type('10').blur() + cy.contains('Tube X is a required field').should('not.exist') + cy.get("input[name='wellYDimension']").focus().blur() + cy.contains('Tube Y is a required field').should('exist') + cy.get("input[name='wellYDimension']").type('10').blur() + cy.contains('Tube Y is a required field').should('not.exist') + + cy.get("input[name='wellBottomShape'][value='flat']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('exist') + cy.get("img[src*='_round.']").should('not.exist') + cy.get("img[src*='_v.']").should('not.exist') + cy.get("input[name='wellBottomShape'][value='u']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('not.exist') + cy.get("img[src*='_round.']").should('exist') + cy.get("img[src*='_v.']").should('not.exist') + cy.get("input[name='wellBottomShape'][value='v']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('not.exist') + cy.get("img[src*='_round.']").should('not.exist') + cy.get("img[src*='_v.']").should('exist') + cy.get("input[name='wellDepth']").focus().blur() + cy.contains('Depth is a required field').should('exist') + cy.get("input[name='wellDepth']").type('10').blur() + cy.contains('Depth is a required field').should('not.exist') + + cy.contains('Add missing info to see labware preview').should( + 'not.exist' + ) + + // test file export + // Try with missing fields + cy.get('button[class*="_export_button_"]').click({ force: true }) + cy.contains( + 'Please resolve all invalid fields in order to export the labware definition' + ).should('exist') + cy.contains('close').click({ force: true }) + + // Brand info + cy.contains('Brand is a required field').should('exist') + cy.get("input[name='brand']").type('TestPro') + cy.contains('Brand is a required field').should('not.exist') + cy.get("input[name='brandId']").type('001') + + // File info + cy.get("input[placeholder='TestPro 96 Aluminum Block 10 µL']").should( + 'exist' + ) + cy.get("input[placeholder='testpro_96_aluminumblock_10ul']").should( + 'exist' + ) + + // All fields present + cy.get('button[class*="_export_button_"]').click({ force: true }) + cy.contains( + 'Please resolve all invalid fields in order to export the labware definition' + ).should('not.exist') + }) + }) + }) + + describe('PCR Tube Strip', () => { + it('does not have a preview image', () => { + cy.contains('Add missing info to see labware preview').should('exist') + }) + + it('tests the whole form and file export', () => { + // verify regularity + cy.get("input[name='homogeneousWells'][value='false']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('exist') + cy.get("input[name='homogeneousWells'][value='true']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('not.exist') + // verify height + cy.get("input[name='labwareZDimension']").type('150').blur() + cy.contains('This labware may be too tall').should('exist') + cy.get("input[name='labwareZDimension']").clear().type('200').blur() + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('exist') + cy.get("input[name='labwareZDimension']").clear().type('75').blur() + cy.contains('This labware may be too tall').should('not.exist') + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('not.exist') + + // verify volume + cy.get("input[name='wellVolume']").focus().blur() + cy.contains('Volume is a required field').should('exist') + cy.get("input[name='wellVolume']").type('10').blur() + cy.contains('Volume is a required field').should('not.exist') + + // circular wells + cy.get("input[name='wellShape'][value='circular']").check({ + force: true, + }) + cy.get("input[name='wellDiameter']").should('exist') + cy.get("input[name='wellXDimension']").should('not.exist') + cy.get("input[name='wellYDimension']").should('not.exist') + cy.get("input[name='wellDiameter']").focus().blur() + cy.contains('Diameter is a required field').should('exist') + cy.get("input[name='wellDiameter']").type('10').blur() + cy.contains('Diameter is a required field').should('not.exist') + + // rectangular wells + cy.get("input[name='wellShape'][value='rectangular']").check({ + force: true, + }) + cy.get("input[name='wellDiameter']").should('not.exist') + cy.get("input[name='wellXDimension']").should('exist') + cy.get("input[name='wellYDimension']").should('exist') + cy.get("input[name='wellXDimension']").focus().blur() + cy.contains('Tube X is a required field').should('exist') + cy.get("input[name='wellXDimension']").type('10').blur() + cy.contains('Tube X is a required field').should('not.exist') + cy.get("input[name='wellYDimension']").focus().blur() + cy.contains('Tube Y is a required field').should('exist') + cy.get("input[name='wellYDimension']").type('10').blur() + cy.contains('Tube Y is a required field').should('not.exist') + + // well shape + + cy.get("input[name='wellBottomShape'][value='flat']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('exist') + cy.get("img[src*='_round.']").should('not.exist') + cy.get("img[src*='_v.']").should('not.exist') + cy.get("input[name='wellBottomShape'][value='u']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('not.exist') + cy.get("img[src*='_round.']").should('exist') + cy.get("img[src*='_v.']").should('not.exist') + cy.get("input[name='wellBottomShape'][value='v']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('not.exist') + cy.get("img[src*='_round.']").should('not.exist') + cy.get("img[src*='_v.']").should('exist') + cy.get("input[name='wellDepth']").focus().blur() + cy.contains('Depth is a required field').should('exist') + cy.get("input[name='wellDepth']").type('10').blur() + cy.contains('Depth is a required field').should('not.exist') + cy.contains('Add missing info to see labware preview').should( + 'not.exist' + ) + + // file export + // Try with missing fields + cy.get('button[class*="_export_button_"]').click({ force: true }) + cy.contains( + 'Please resolve all invalid fields in order to export the labware definition' + ).should('exist') + cy.contains('close').click({ force: true }) + + // Brand info + cy.contains('Brand is a required field').should('exist') + cy.get("input[name='brand']").type('TestPro') + cy.contains('Brand is a required field').should('not.exist') + cy.get("input[name='brandId']").type('001') + + // File info + cy.get("input[placeholder='TestPro 96 Aluminum Block 10 µL']").should( + 'exist' + ) + cy.get("input[placeholder='testpro_96_aluminumblock_10ul']").should( + 'exist' + ) + + // All fields present + cy.get('button[class*="_export_button_"]').click({ force: true }) + cy.contains( + 'Please resolve all invalid fields in order to export the labware definition' + ).should('not.exist') + }) + }) + + describe('PCR Plate', () => { + beforeEach(() => { + cy.get('label') + .contains('What type of labware are you creating?') + .children() + .first() + .trigger('mousedown') + cy.get('*[class^="_option_label"]') + .contains('Tubes / Plates + Opentrons Aluminum Block') + .click() + + cy.get('label') + .contains('Which aluminum block?') + .children() + .first() + .trigger('mousedown') + cy.get('*[class^="_option_label"]').contains('96 well').click() + + cy.get('label') + .contains('What labware is on top of your aluminum block?') + .children() + .first() + .trigger('mousedown') + cy.get('*[class^="_option_label"]').contains('PCR Plate').click() + + cy.contains('start creating labware').click({ force: true }) + }) + it('does not have a preview image', () => { + cy.contains('Add missing info to see labware preview').should('exist') + }) + + it('tests the whole form and file export', () => { + // regularity + cy.get("input[name='homogeneousWells'][value='false']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('exist') + cy.get("input[name='homogeneousWells'][value='true']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('not.exist') + + // height + cy.get("input[name='labwareZDimension']").type('150').blur() + cy.contains('This labware may be too tall').should('exist') + cy.get("input[name='labwareZDimension']").clear().type('200').blur() + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('exist') + cy.get("input[name='labwareZDimension']").clear().type('75').blur() + cy.contains('This labware may be too tall').should('not.exist') + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('not.exist') + + // volume + cy.get("input[name='wellVolume']").focus().blur() + cy.contains('Volume is a required field').should('exist') + cy.get("input[name='wellVolume']").type('10').blur() + cy.contains('Volume is a required field').should('not.exist') + + // circular well shape + cy.get("input[name='wellShape'][value='circular']").check({ + force: true, + }) + cy.get("input[name='wellDiameter']").should('exist') + cy.get("input[name='wellXDimension']").should('not.exist') + cy.get("input[name='wellYDimension']").should('not.exist') + cy.get("input[name='wellDiameter']").focus().blur() + cy.contains('Diameter is a required field').should('exist') + cy.get("input[name='wellDiameter']").type('10').blur() + cy.contains('Diameter is a required field').should('not.exist') + + // rectangular well shape + cy.get("input[name='wellShape'][value='rectangular']").check({ + force: true, + }) + cy.get("input[name='wellDiameter']").should('not.exist') + cy.get("input[name='wellXDimension']").should('exist') + cy.get("input[name='wellYDimension']").should('exist') + cy.get("input[name='wellXDimension']").focus().blur() + cy.contains('Well X is a required field').should('exist') + cy.get("input[name='wellXDimension']").type('10').blur() + cy.contains('Well X is a required field').should('not.exist') + cy.get("input[name='wellYDimension']").focus().blur() + cy.contains('Well Y is a required field').should('exist') + cy.get("input[name='wellYDimension']").type('10').blur() + cy.contains('Well Y is a required field').should('not.exist') + + // well bottom + + cy.get("input[name='wellBottomShape'][value='flat']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('exist') + cy.get("img[src*='_round.']").should('not.exist') + cy.get("img[src*='_v.']").should('not.exist') + cy.get("input[name='wellBottomShape'][value='u']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('not.exist') + cy.get("img[src*='_round.']").should('exist') + cy.get("img[src*='_v.']").should('not.exist') + cy.get("input[name='wellBottomShape'][value='v']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('not.exist') + cy.get("img[src*='_round.']").should('not.exist') + cy.get("img[src*='_v.']").should('exist') + cy.get("input[name='wellDepth']").focus().blur() + cy.contains('Depth is a required field').should('exist') + cy.get("input[name='wellDepth']").type('10').blur() + cy.contains('Depth is a required field').should('not.exist') + + cy.contains('Add missing info to see labware preview').should( + 'not.exist' + ) + + // file export + // Try with missing fields + cy.get('button[class*="_export_button_"]').click({ force: true }) + cy.contains( + 'Please resolve all invalid fields in order to export the labware definition' + ).should('exist') + cy.contains('close').click({ force: true }) + + // Brand info + cy.contains('Brand is a required field').should('exist') + cy.get("input[name='brand']").type('TestPro') + cy.contains('Brand is a required field').should('not.exist') + cy.get("input[name='brandId']").type('001') + + // File info + cy.get("input[placeholder='TestPro 96 Aluminum Block 10 µL']").should( + 'exist' + ) + cy.get("input[placeholder='testpro_96_aluminumblock_10ul']").should( + 'exist' + ) + + // All fields present + cy.get('button[class*="_export_button_"]').click({ force: true }) + cy.contains( + 'Please resolve all invalid fields in order to export the labware definition' + ).should('not.exist') + }) + }) + }) + + describe('24 Well', () => { + describe('Tubes', () => { + it('does not have a preview image', () => { + cy.contains('Add missing info to see labware preview').should('exist') + }) + + it('tests the whole form and file export', () => { + cy.visit('/create') + cy.viewport('macbook-15') + cy.get('label') + .contains('What type of labware are you creating?') + .children() + .first() + .trigger('mousedown') + cy.get('*[class^="_option_label"]') + .contains('Tubes / Plates + Opentrons Aluminum Block') + .click() + + cy.get('label') + .contains('Which aluminum block?') + .children() + .first() + .trigger('mousedown') + cy.get('*[class^="_option_label"]').contains('24 well').click() + + cy.get('label') + .contains('What labware is on top of your aluminum block?') + .should('not.exist') + + cy.contains('start creating labware').click({ force: true }) + cy.get("input[name='homogeneousWells'][value='false']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('exist') + cy.get("input[name='homogeneousWells'][value='true']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('not.exist') + + // height + cy.get("input[name='labwareZDimension']").type('150').blur() + cy.contains('This labware may be too tall').should('exist') + cy.get("input[name='labwareZDimension']").clear().type('200').blur() + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('exist') + cy.get("input[name='labwareZDimension']").clear().type('75').blur() + cy.contains('This labware may be too tall').should('not.exist') + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('not.exist') + + // volume + + cy.get("input[name='wellVolume']").focus().blur() + cy.contains('Volume is a required field').should('exist') + cy.get("input[name='wellVolume']").type('10').blur() + cy.contains('Volume is a required field').should('not.exist') + + // circular wells + cy.get("input[name='wellShape'][value='circular']").check({ + force: true, + }) + cy.get("input[name='wellDiameter']").should('exist') + cy.get("input[name='wellXDimension']").should('not.exist') + cy.get("input[name='wellYDimension']").should('not.exist') + cy.get("input[name='wellDiameter']").focus().blur() + cy.contains('Diameter is a required field').should('exist') + cy.get("input[name='wellDiameter']").type('10').blur() + cy.contains('Diameter is a required field').should('not.exist') + + // rectangular wells + cy.get("input[name='wellShape'][value='rectangular']").check({ + force: true, + }) + cy.get("input[name='wellDiameter']").should('not.exist') + cy.get("input[name='wellXDimension']").should('exist') + cy.get("input[name='wellYDimension']").should('exist') + cy.get("input[name='wellXDimension']").focus().blur() + cy.contains('Well X is a required field').should('exist') + cy.get("input[name='wellXDimension']").type('10').blur() + cy.contains('Well X is a required field').should('not.exist') + cy.get("input[name='wellYDimension']").focus().blur() + cy.contains('Well Y is a required field').should('exist') + cy.get("input[name='wellYDimension']").type('10').blur() + cy.contains('Well Y is a required field').should('not.exist') + + // well bottom shape + cy.get("input[name='wellBottomShape'][value='flat']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('exist') + cy.get("img[src*='_round.']").should('not.exist') + cy.get("img[src*='_v.']").should('not.exist') + cy.get("input[name='wellBottomShape'][value='u']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('not.exist') + cy.get("img[src*='_round.']").should('exist') + cy.get("img[src*='_v.']").should('not.exist') + cy.get("input[name='wellBottomShape'][value='v']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('not.exist') + cy.get("img[src*='_round.']").should('not.exist') + cy.get("img[src*='_v.']").should('exist') + cy.get("input[name='wellDepth']").focus().blur() + cy.contains('Depth is a required field').should('exist') + cy.get("input[name='wellDepth']").type('10').blur() + cy.contains('Depth is a required field').should('not.exist') + + cy.contains('Add missing info to see labware preview').should( + 'not.exist' + ) + + // file export + // Try with missing fields + cy.get('button[class*="_export_button_"]').click({ force: true }) + cy.contains( + 'Please resolve all invalid fields in order to export the labware definition' + ).should('exist') + cy.contains('close').click({ force: true }) + + // Brand info + cy.contains('Brand is a required field').should('exist') + cy.get("input[name='brand']").type('TestPro') + cy.contains('Brand is a required field').should('not.exist') + cy.get("input[name='brandId']").type('001') + + // File info + cy.get("input[placeholder='TestPro 24 Aluminum Block 10 µL']").should( + 'exist' + ) + cy.get("input[placeholder='testpro_24_aluminumblock_10ul']").should( + 'exist' + ) + + // All fields present + cy.get('button[class*="_export_button_"]').click({ force: true }) + cy.contains( + 'Please resolve all invalid fields in order to export the labware definition' + ).should('not.exist') + }) + }) + }) +}) diff --git a/labware-library/cypress/e2e/labware-creator/tubesRack.cy.js b/labware-library/cypress/e2e/labware-creator/tubesRack.cy.js new file mode 100644 index 00000000000..64ff26bcdc3 --- /dev/null +++ b/labware-library/cypress/e2e/labware-creator/tubesRack.cy.js @@ -0,0 +1,401 @@ +// Scrolling seems wonky, so I disabled checking to see if +// an element is in view before clicking or checking with +// { force: true } + +context('Tubes and Rack', () => { + describe('Six tubes', () => { + before(() => { + cy.visit('/create') + cy.viewport('macbook-15') + cy.contains('NO').click({ force: true }) + cy.get('label') + .contains('What type of labware are you creating?') + .children() + .first() + .trigger('mousedown') + cy.get('*[class^="_option_label"]').contains('Tubes + Tube Rack').click() + + cy.get('label') + .contains('Which tube rack?') + .children() + .first() + .trigger('mousedown') + cy.get('*[class^="_option_label"]').contains('6 tubes').click() + + cy.contains('start creating labware').click({ force: true }) + }) + + it('creates a tuberack with 16 tubes', () => { + // does not have a preview image + cy.contains('Add missing info to see labware preview').should('exist') + + // Verify regularity + cy.get("input[name='homogeneousWells'][value='false']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('exist') + cy.get("input[name='homogeneousWells'][value='true']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('not.exist') + + // Verify height + cy.get("input[name='labwareZDimension']").type('150').blur() + cy.contains('This labware may be too tall').should('exist') + cy.get("input[name='labwareZDimension']").clear().type('200').blur() + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('exist') + cy.get("input[name='labwareZDimension']").clear().type('75').blur() + cy.contains('This labware may be too tall').should('not.exist') + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('not.exist') + + // Verify volume + cy.get("input[name='wellVolume']").focus().blur() + cy.contains('Volume is a required field').should('exist') + cy.get("input[name='wellVolume']").type('10').blur() + cy.contains('Volume is a required field').should('not.exist') + + // Well shape tests + + // circular wells + cy.get("input[name='wellShape'][value='circular']").check({ + force: true, + }) + cy.get("input[name='wellDiameter']").should('exist') + cy.get("input[name='wellXDimension']").should('not.exist') + cy.get("input[name='wellYDimension']").should('not.exist') + cy.get("input[name='wellDiameter']").focus().blur() + cy.contains('Diameter is a required field').should('exist') + cy.get("input[name='wellDiameter']").type('10').blur() + cy.contains('Diameter is a required field').should('not.exist') + + // rectangular wells + cy.get("input[name='wellShape'][value='rectangular']").check({ + force: true, + }) + cy.get("input[name='wellDiameter']").should('not.exist') + cy.get("input[name='wellXDimension']").should('exist') + cy.get("input[name='wellYDimension']").should('exist') + cy.get("input[name='wellXDimension']").focus().blur() + cy.contains('Tube X is a required field').should('exist') + cy.get("input[name='wellXDimension']").type('10').blur() + cy.contains('Tube X is a required field').should('not.exist') + cy.get("input[name='wellYDimension']").focus().blur() + cy.contains('Tube Y is a required field').should('exist') + cy.get("input[name='wellYDimension']").type('10').blur() + cy.contains('Tube Y is a required field').should('not.exist') + + // well bottom shape and depth + cy.get("input[name='wellBottomShape'][value='flat']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('exist') + cy.get("img[src*='_round.']").should('not.exist') + cy.get("img[src*='_v.']").should('not.exist') + cy.get("input[name='wellBottomShape'][value='u']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('not.exist') + cy.get("img[src*='_round.']").should('exist') + cy.get("img[src*='_v.']").should('not.exist') + cy.get("input[name='wellBottomShape'][value='v']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('not.exist') + cy.get("img[src*='_round.']").should('not.exist') + cy.get("img[src*='_v.']").should('exist') + cy.get("input[name='wellDepth']").focus().blur() + cy.contains('Depth is a required field').should('exist') + cy.get("input[name='wellDepth']").type('10').blur() + cy.contains('Depth is a required field').should('not.exist') + + cy.contains('Add missing info to see labware preview').should('not.exist') + + // Verify file export + // Brand field should not be shown for Opentrons tube rack (aka non-custom) + cy.contains('Brand is a required field').should('not.exist') + + // File info + cy.get( + "input[placeholder='Opentrons 6 Tube Rack with Generic 0.01 mL']" + ).should('exist') + cy.get("input[placeholder='opentrons_6_tuberack_10ul']").should('exist') + + // All fields present + cy.get('button[class*="_export_button_"]').click({ force: true }) + cy.contains( + 'Please resolve all invalid fields in order to export the labware definition' + ).should('not.exist') + }) + }) + + describe('Fifteen tubes', () => { + before(() => { + cy.visit('/create') + cy.viewport('macbook-15') + cy.contains('NO').click({ force: true }) + + cy.get('label') + .contains('What type of labware are you creating?') + .children() + .first() + .trigger('mousedown') + cy.get('*[class^="_option_label"]').contains('Tubes + Tube Rack').click() + + cy.get('label') + .contains('Which tube rack?') + .children() + .first() + .trigger('mousedown') + cy.get('*[class^="_option_label"]').contains('15 tubes').click() + + cy.contains('start creating labware').click({ force: true }) + }) + + it('creates a tuberack with 15 tubes', () => { + cy.contains('Add missing info to see labware preview').should('exist') + + // Verify regularity + cy.get("input[name='homogeneousWells'][value='false']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('exist') + cy.get("input[name='homogeneousWells'][value='true']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('not.exist') + + // Verify height + cy.get("input[name='labwareZDimension']").type('150').blur() + cy.contains('This labware may be too tall').should('exist') + cy.get("input[name='labwareZDimension']").clear().type('200').blur() + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('exist') + cy.get("input[name='labwareZDimension']").clear().type('75').blur() + cy.contains('This labware may be too tall').should('not.exist') + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('not.exist') + + // Verify volume + cy.get("input[name='wellVolume']").focus().blur() + cy.contains('Volume is a required field').should('exist') + cy.get("input[name='wellVolume']").type('10').blur() + cy.contains('Volume is a required field').should('not.exist') + + // Well shape + // Verify circular wells + cy.get("input[name='wellShape'][value='circular']").check({ + force: true, + }) + cy.get("input[name='wellDiameter']").should('exist') + cy.get("input[name='wellXDimension']").should('not.exist') + cy.get("input[name='wellYDimension']").should('not.exist') + cy.get("input[name='wellDiameter']").focus().blur() + cy.contains('Diameter is a required field').should('exist') + cy.get("input[name='wellDiameter']").type('10').blur() + cy.contains('Diameter is a required field').should('not.exist') + + // Verify rectangular wells + cy.get("input[name='wellShape'][value='rectangular']").check({ + force: true, + }) + cy.get("input[name='wellDiameter']").should('not.exist') + cy.get("input[name='wellXDimension']").should('exist') + cy.get("input[name='wellYDimension']").should('exist') + cy.get("input[name='wellXDimension']").focus().blur() + cy.contains('Tube X is a required field').should('exist') + cy.get("input[name='wellXDimension']").type('10').blur() + cy.contains('Tube X is a required field').should('not.exist') + cy.get("input[name='wellYDimension']").focus().blur() + cy.contains('Tube Y is a required field').should('exist') + cy.get("input[name='wellYDimension']").type('10').blur() + cy.contains('Tube Y is a required field').should('not.exist') + + // verify well bottom shape and depth + cy.get("input[name='wellBottomShape'][value='flat']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('exist') + cy.get("img[src*='_round.']").should('not.exist') + cy.get("img[src*='_v.']").should('not.exist') + cy.get("input[name='wellBottomShape'][value='u']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('not.exist') + cy.get("img[src*='_round.']").should('exist') + cy.get("img[src*='_v.']").should('not.exist') + cy.get("input[name='wellBottomShape'][value='v']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('not.exist') + cy.get("img[src*='_round.']").should('not.exist') + cy.get("img[src*='_v.']").should('exist') + cy.get("input[name='wellDepth']").focus().blur() + cy.contains('Depth is a required field').should('exist') + cy.get("input[name='wellDepth']").type('10').blur() + cy.contains('Depth is a required field').should('not.exist') + + cy.contains('Add missing info to see labware preview').should('not.exist') + + // Verify the file export + // Brand field should not be shown for Opentrons tube rack (aka non-custom) + cy.contains('Brand is a required field').should('not.exist') + + // File info + cy.get( + "input[placeholder='Opentrons 15 Tube Rack with Generic 0.01 mL']" + ).should('exist') + cy.get("input[placeholder='opentrons_15_tuberack_10ul']").should('exist') + + // All fields present + cy.get('button[class*="_export_button_"]').click({ force: true }) + cy.contains( + 'Please resolve all invalid fields in order to export the labware definition' + ).should('not.exist') + }) + }) + + describe('Twentyfour tubes', () => { + before(() => { + cy.visit('/create') + cy.viewport('macbook-15') + cy.contains('NO').click({ force: true }) + + cy.get('label') + .contains('What type of labware are you creating?') + .children() + .first() + .trigger('mousedown') + cy.get('*[class^="_option_label"]').contains('Tubes + Tube Rack').click() + + cy.get('label') + .contains('Which tube rack?') + .children() + .first() + .trigger('mousedown') + cy.get('*[class^="_option_label"]').contains('24 tubes').click() + + cy.contains('start creating labware').click({ force: true }) + }) + + it('create a tuberack with 24 tubes', () => { + cy.contains('Add missing info to see labware preview').should('exist') + + // Verify regularity + cy.get("input[name='homogeneousWells'][value='false']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('exist') + cy.get("input[name='homogeneousWells'][value='true']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('not.exist') + + // Verify height + cy.get("input[name='labwareZDimension']").type('150').blur() + cy.contains('This labware may be too tall').should('exist') + cy.get("input[name='labwareZDimension']").clear().type('200').blur() + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('exist') + cy.get("input[name='labwareZDimension']").clear().type('75').blur() + cy.contains('This labware may be too tall').should('not.exist') + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('not.exist') + + // Verify volume + cy.get("input[name='wellVolume']").focus().blur() + cy.contains('Volume is a required field').should('exist') + cy.get("input[name='wellVolume']").type('10').blur() + cy.contains('Volume is a required field').should('not.exist') + + // Verify well shape + cy.get("input[name='wellShape'][value='circular']").check({ + force: true, + }) + cy.get("input[name='wellDiameter']").should('exist') + cy.get("input[name='wellXDimension']").should('not.exist') + cy.get("input[name='wellYDimension']").should('not.exist') + cy.get("input[name='wellDiameter']").focus().blur() + cy.contains('Diameter is a required field').should('exist') + cy.get("input[name='wellDiameter']").type('10').blur() + cy.contains('Diameter is a required field').should('not.exist') + + // verify rectangular wells + cy.get("input[name='wellShape'][value='rectangular']").check({ + force: true, + }) + cy.get("input[name='wellDiameter']").should('not.exist') + cy.get("input[name='wellXDimension']").should('exist') + cy.get("input[name='wellYDimension']").should('exist') + cy.get("input[name='wellXDimension']").focus().blur() + cy.contains('Tube X is a required field').should('exist') + cy.get("input[name='wellXDimension']").type('10').blur() + cy.contains('Tube X is a required field').should('not.exist') + cy.get("input[name='wellYDimension']").focus().blur() + cy.contains('Tube Y is a required field').should('exist') + cy.get("input[name='wellYDimension']").type('10').blur() + cy.contains('Tube Y is a required field').should('not.exist') + + // verify well bottom shape and depth + cy.get("input[name='wellBottomShape'][value='flat']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('exist') + cy.get("img[src*='_round.']").should('not.exist') + cy.get("img[src*='_v.']").should('not.exist') + cy.get("input[name='wellBottomShape'][value='u']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('not.exist') + cy.get("img[src*='_round.']").should('exist') + cy.get("img[src*='_v.']").should('not.exist') + cy.get("input[name='wellBottomShape'][value='v']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('not.exist') + cy.get("img[src*='_round.']").should('not.exist') + cy.get("img[src*='_v.']").should('exist') + cy.get("input[name='wellDepth']").focus().blur() + cy.contains('Depth is a required field').should('exist') + cy.get("input[name='wellDepth']").type('10').blur() + cy.contains('Depth is a required field').should('not.exist') + + cy.contains('Add missing info to see labware preview').should('not.exist') + + // verify file export + // Brand field should not be shown for Opentrons tube rack (aka non-custom) + cy.contains('Brand is a required field').should('not.exist') + + // File info + cy.get( + "input[placeholder='Opentrons 24 Tube Rack with Generic 0.01 mL']" + ).should('exist') + cy.get("input[placeholder='opentrons_24_tuberack_10ul']").should('exist') + + // All fields present + cy.get('button[class*="_export_button_"]').click({ force: true }) + cy.contains( + 'Please resolve all invalid fields in order to export the labware definition' + ).should('not.exist') + }) + }) +}) diff --git a/labware-library/cypress/e2e/labware-creator/wellPlate.cy.js b/labware-library/cypress/e2e/labware-creator/wellPlate.cy.js new file mode 100644 index 00000000000..33d7f02303e --- /dev/null +++ b/labware-library/cypress/e2e/labware-creator/wellPlate.cy.js @@ -0,0 +1,223 @@ +// NOTE: This uses data that produces a labware definition file +// that cannot be imported. The creator probably shouldn't allow +// a user to do this. + +// Scrolling seems wonky, so I disabled checking to see if +// an element is in view before clicking or checking with +// { force: true } + +context('Well Plates', () => { + before(() => { + cy.visit('/create') + cy.viewport('macbook-15') + cy.contains('NO').click({ force: true }) + }) + + describe('Create a well plate', () => { + before(() => { + cy.get('label') + .contains('What type of labware are you creating?') + .children() + .first() + .trigger('mousedown') + cy.get('*[class^="_option_label"]').contains('Well Plate').click() + cy.get('button').contains('start creating labware').click({ force: true }) + }) + it('creates a wellplate', () => { + cy.contains('Add missing info to see labware preview').should('exist') + + // Verify regularity + cy.get("input[name='homogeneousWells'][value='false']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('exist') + cy.get("input[name='homogeneousWells'][value='true']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('not.exist') + + // Verify footprint + cy.get("input[name='footprintXDimension']").type('150').blur() + cy.contains( + 'Your labware is too large to fit in a single slot properly. Please fill out this form to request a custom labware definition.' + ).should('exist') + cy.get("input[name='footprintXDimension']").clear().type('127').blur() + cy.contains( + 'Your labware is too large to fit in a single slot properly. Please fill out this form to request a custom labware definition.' + ).should('not.exist') + cy.get("input[name='footprintYDimension']").type('150').blur() + cy.contains( + 'Your labware is too large to fit in a single slot properly. Please fill out this form to request a custom labware definition.' + ).should('exist') + cy.get("input[name='footprintYDimension']").clear().type('85').blur() + cy.contains( + 'Your labware is too large to fit in a single slot properly. Please fill out this form to request a custom labware definition.' + ).should('not.exist') + + // Verify height + cy.get("input[name='labwareZDimension']").type('150').blur() + cy.contains('This labware may be too tall').should('exist') + cy.get("input[name='labwareZDimension']").clear().type('200').blur() + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('exist') + cy.get("input[name='labwareZDimension']").clear().type('75').blur() + cy.contains('This labware may be too tall').should('not.exist') + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('not.exist') + + // Verify number of rows + cy.get("input[name='gridRows']").focus().blur() + cy.contains('Number of rows is a required field').should('exist') + cy.get("input[name='gridRows']").type('8').blur() + cy.contains('Number of rows is a required field').should('not.exist') + + // Verify rows are evenly spaced + cy.get("input[name='regularRowSpacing'][value='false']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('exist') + cy.get("input[name='regularRowSpacing'][value='true']").check({ + force: true, + }) + + // Verify number of columns + cy.get("input[name='gridColumns']").focus().blur() + cy.contains('Number of columns is a required field').should('exist') + cy.get("input[name='gridColumns']").type('10').blur() + cy.contains('Number of columns is a required field').should('not.exist') + + // Verify columns are evenly spaced + cy.get("input[name='regularColumnSpacing'][value='false']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('exist') + cy.get("input[name='regularColumnSpacing'][value='true']").check({ + force: true, + }) + cy.contains( + 'Your labware is not compatible with the Labware Creator' + ).should('not.exist') + + // Verify volume + cy.get("input[name='wellVolume']").focus().blur() + cy.contains('Volume is a required field').should('exist') + cy.get("input[name='wellVolume']").type('100').blur() + cy.contains('Volume is a required field').should('not.exist') + + // verify circular wells + cy.get("input[name='wellShape'][value='circular']").check({ + force: true, + }) + cy.get("input[name='wellDiameter']").should('exist') + cy.get("input[name='wellXDimension']").should('not.exist') + cy.get("input[name='wellYDimension']").should('not.exist') + cy.get("input[name='wellDiameter']").focus().blur() + cy.contains('Diameter is a required field').should('exist') + cy.get("input[name='wellDiameter']").type('10').blur() + cy.contains('Diameter is a required field').should('not.exist') + + // verify rectangular wells + cy.get("input[name='wellShape'][value='rectangular']").check({ + force: true, + }) + cy.get("input[name='wellDiameter']").should('not.exist') + cy.get("input[name='wellXDimension']").should('exist') + cy.get("input[name='wellYDimension']").should('exist') + cy.get("input[name='wellXDimension']").focus().blur() + cy.contains('Well X is a required field').should('exist') + cy.get("input[name='wellXDimension']").type('8').blur() + cy.contains('Well X is a required field').should('not.exist') + cy.get("input[name='wellYDimension']").focus().blur() + cy.contains('Well Y is a required field').should('exist') + cy.get("input[name='wellYDimension']").type('8').blur() + cy.contains('Well Y is a required field').should('not.exist') + + // Verify well bottom shape and depth + cy.get("input[name='wellBottomShape'][value='flat']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('exist') + cy.get("img[src*='_round.']").should('not.exist') + cy.get("img[src*='_v.']").should('not.exist') + cy.get("input[name='wellBottomShape'][value='u']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('not.exist') + cy.get("img[src*='_round.']").should('exist') + cy.get("img[src*='_v.']").should('not.exist') + cy.get("input[name='wellBottomShape'][value='v']").check({ + force: true, + }) + cy.get("img[src*='_flat.']").should('not.exist') + cy.get("img[src*='_round.']").should('not.exist') + cy.get("img[src*='_v.']").should('exist') + cy.get("input[name='wellDepth']").focus().blur() + cy.contains('Depth is a required field').should('exist') + cy.get("input[name='wellDepth']").type('10').blur() + cy.contains('Depth is a required field').should('not.exist') + + // Verify well spacing + cy.get("input[name='gridSpacingX']").focus().blur() + cy.contains('X Spacing (Xs) is a required field').should('exist') + cy.get("input[name='gridSpacingX']").type('12').blur() + cy.contains('X Spacing (Xs) is a required field').should('not.exist') + cy.get("input[name='gridSpacingY']").focus().blur() + cy.contains('Y Spacing (Ys) is a required field').should('exist') + cy.get("input[name='gridSpacingY']").type('10').blur() + cy.contains('Y Spacing (Ys) is a required field').should('not.exist') + + // Verify grid offset + cy.get("input[name='gridOffsetX']").focus().blur() + cy.contains('X Offset (Xo) is a required field').should('exist') + cy.get("input[name='gridOffsetX']").type('10').blur() + cy.contains('X Offset (Xo) is a required field').should('not.exist') + cy.get("input[name='gridOffsetY']").focus().blur() + cy.contains('Y Offset (Yo) is a required field').should('exist') + cy.get("input[name='gridOffsetY']").type('8').blur() + cy.contains('Y Offset (Yo) is a required field').should('not.exist') + + cy.contains('Add missing info to see labware preview').should('not.exist') + cy.contains( + 'Please double-check well size, Y Spacing, and Y Offset.' + ).should('not.exist') + + // Verify file export + // Try with missing fields + cy.get('button[class*="_export_button_"]').click({ force: true }) + cy.contains( + 'Please resolve all invalid fields in order to export the labware definition' + ).should('exist') + cy.contains('close').click({ force: true }) + + // Brand info + cy.contains('Brand is a required field').should('exist') + cy.get("input[name='brand']").type('TestPro') + cy.contains('Brand is a required field').should('not.exist') + cy.get("input[name='brandId']").type('001') + + // File info + cy.get("input[placeholder='TestPro 80 Well Plate 100 µL']").should( + 'exist' + ) + cy.get("input[placeholder='testpro_80_wellplate_100ul']").should('exist') + + // All fields present + cy.get('button[class*="_export_button_"]').click({ force: true }) + cy.contains( + 'Please resolve all invalid fields in order to export the labware definition' + ).should('not.exist') + + // TODO IMMEDIATELY match against fixture ??? Is this not happening? + }) + }) +}) diff --git a/labware-library/cypress/integration/navigation.spec.js b/labware-library/cypress/e2e/navigation.cy.js similarity index 100% rename from labware-library/cypress/integration/navigation.spec.js rename to labware-library/cypress/e2e/navigation.cy.js diff --git a/labware-library/cypress/integration/labware-creator/reservoir.spec.js b/labware-library/cypress/integration/labware-creator/reservoir.spec.js deleted file mode 100644 index 88b23084aa9..00000000000 --- a/labware-library/cypress/integration/labware-creator/reservoir.spec.js +++ /dev/null @@ -1,230 +0,0 @@ -// Scrolling seems wonky, so I disabled checking to see if -// an element is in view before clicking or checking with -// { force: true } - -context('Reservoirs', () => { - before(() => { - cy.visit('/create') - cy.viewport('macbook-15') - cy.contains('NO').click({ force: true }) - }) - - describe('Create a reservoir', () => { - before(() => { - // TODO(IL, 2021-05-15): give Dropdown component semantic selectors for E2E - cy.contains('What type of labware are you creating?') - .children() - .first() - .trigger('mousedown') - cy.get('*[class^="_option_label"]').contains('Reservoir').click() - cy.contains('Reservoir').click({ force: true }) - cy.contains('start creating labware').click({ force: true }) - }) - - it('does not have a preview image', () => { - cy.contains('Add missing info to see labware preview').should('exist') - }) - - it('tests regularity', () => { - cy.get("input[name='homogeneousWells'][value='false']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('exist') - cy.get("input[name='homogeneousWells'][value='true']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('not.exist') - }) - - it('tests footprint', () => { - cy.get("input[name='footprintXDimension']").type('150').blur() - cy.contains( - 'Your labware is too large to fit in a single slot properly. Please fill out this form to request a custom labware definition.' - ).should('exist') - cy.get("input[name='footprintXDimension']").clear().type('127').blur() - cy.contains( - 'Your labware is too large to fit in a single slot properly. Please fill out this form to request a custom labware definition.' - ).should('not.exist') - cy.get("input[name='footprintYDimension']").type('150').blur() - cy.contains( - 'Your labware is too large to fit in a single slot properly. Please fill out this form to request a custom labware definition.' - ).should('exist') - cy.get("input[name='footprintYDimension']").clear().type('85').blur() - cy.contains( - 'Your labware is too large to fit in a single slot properly. Please fill out this form to request a custom labware definition.' - ).should('not.exist') - }) - - it('tests height', () => { - cy.get("input[name='labwareZDimension']").type('150').blur() - cy.contains('This labware may be too tall').should('exist') - cy.get("input[name='labwareZDimension']").clear().type('200').blur() - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('exist') - cy.get("input[name='labwareZDimension']").clear().type('75').blur() - cy.contains('This labware may be too tall').should('not.exist') - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('not.exist') - }) - - describe('Grid tests', () => { - it('tests number of rows', () => { - cy.get("input[name='gridRows']").focus().blur() - cy.contains('Number of rows is a required field').should('exist') - cy.get("input[name='gridRows']").type('1').blur() - cy.contains('Number of rows is a required field').should('not.exist') - }) - - it('should not ask if all of your rows evenly spaced, since we only have one row', () => { - cy.get("input[name='regularRowSpacing'][value='false']").should( - 'not.exist' - ) - }) - - it('tests number of columns', () => { - cy.get("input[name='gridColumns']").focus().blur() - cy.contains('Number of columns is a required field').should('exist') - cy.get("input[name='gridColumns']").type('10').blur() - cy.contains('Number of columns is a required field').should('not.exist') - }) - - it('tests are all of your columns evenly spaced', () => { - cy.get("input[name='regularColumnSpacing'][value='false']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('exist') - cy.get("input[name='regularColumnSpacing'][value='true']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('not.exist') - }) - }) - - it('tests volume', () => { - cy.get("input[name='wellVolume']").focus().blur() - cy.contains('Volume is a required field').should('exist') - cy.get("input[name='wellVolume']").type('250').blur() - cy.contains('Volume is a required field').should('not.exist') - }) - - describe('Well shape tests', () => { - it('tests circular wells', () => { - cy.get("input[name='wellShape'][value='circular']").check({ - force: true, - }) - cy.get("input[name='wellDiameter']").should('exist') - cy.get("input[name='wellXDimension']").should('not.exist') - cy.get("input[name='wellYDimension']").should('not.exist') - cy.get("input[name='wellDiameter']").focus().blur() - cy.contains('Diameter is a required field').should('exist') - cy.get("input[name='wellDiameter']").type('10').blur() - cy.contains('Diameter is a required field').should('not.exist') - }) - - it('tests rectangular wells', () => { - cy.get("input[name='wellShape'][value='rectangular']").check({ - force: true, - }) - cy.get("input[name='wellDiameter']").should('not.exist') - cy.get("input[name='wellXDimension']").should('exist') - cy.get("input[name='wellYDimension']").should('exist') - cy.get("input[name='wellXDimension']").focus().blur() - cy.contains('Well X is a required field').should('exist') - cy.get("input[name='wellXDimension']").type('8').blur() - cy.contains('Well X is a required field').should('not.exist') - cy.get("input[name='wellYDimension']").focus().blur() - cy.contains('Well Y is a required field').should('exist') - cy.get("input[name='wellYDimension']").type('60').blur() - cy.contains('Well Y is a required field').should('not.exist') - }) - - it('tests well bottom shape and depth', () => { - cy.get("input[name='wellBottomShape'][value='flat']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('exist') - cy.get("img[src*='_round.']").should('not.exist') - cy.get("img[src*='_v.']").should('not.exist') - cy.get("input[name='wellBottomShape'][value='u']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('not.exist') - cy.get("img[src*='_round.']").should('exist') - cy.get("img[src*='_v.']").should('not.exist') - cy.get("input[name='wellBottomShape'][value='v']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('not.exist') - cy.get("img[src*='_round.']").should('not.exist') - cy.get("img[src*='_v.']").should('exist') - cy.get("input[name='wellDepth']").focus().blur() - cy.contains('Depth is a required field').should('exist') - cy.get("input[name='wellDepth']").type('70').blur() - cy.contains('Depth is a required field').should('not.exist') - }) - - it('tests well spacing', () => { - cy.get("input[name='gridSpacingX']").focus().blur() - cy.contains('X Spacing (Xs) is a required field').should('exist') - cy.get("input[name='gridSpacingX']").type('12').blur() - cy.contains('X Spacing (Xs) is a required field').should('not.exist') - }) - - it('tests grid offset', () => { - cy.get("input[name='gridOffsetX']").focus().blur() - cy.contains('X Offset (Xo) is a required field').should('exist') - cy.get("input[name='gridOffsetX']").type('10').blur() - cy.contains('X Offset (Xo) is a required field').should('not.exist') - cy.get("input[name='gridOffsetY']").focus().blur() - cy.contains('Y Offset (Yo) is a required field').should('exist') - cy.get("input[name='gridOffsetY']").type('45').blur() - cy.contains('Y Offset (Yo) is a required field').should('not.exist') - }) - - it('does has a preview image', () => { - cy.contains('Add missing info to see labware preview').should( - 'not.exist' - ) - }) - - it('tests the file export', () => { - // Try with missing fields - cy.get('button[class*="_export_button_"]').click({ force: true }) - cy.contains( - 'Please resolve all invalid fields in order to export the labware definition' - ).should('exist') - cy.contains('close').click({ force: true }) - - // Brand info - cy.contains('Brand is a required field').should('exist') - cy.get("input[name='brand']").type('TestPro') - cy.contains('Brand is a required field').should('not.exist') - cy.get("input[name='brandId']").type('001') - - // File info - cy.get("input[placeholder='TestPro 10 Reservoir 250 µL']").should( - 'exist' - ) - cy.get("input[placeholder='testpro_10_reservoir_250ul']").should( - 'exist' - ) - - // All fields present - cy.get('button[class*="_export_button_"]').click({ force: true }) - cy.contains( - 'Please resolve all invalid fields in order to export the labware definition' - ).should('not.exist') - }) - }) - }) -}) diff --git a/labware-library/cypress/integration/labware-creator/tubesBlock.spec.js b/labware-library/cypress/integration/labware-creator/tubesBlock.spec.js deleted file mode 100644 index 8d284e00d97..00000000000 --- a/labware-library/cypress/integration/labware-creator/tubesBlock.spec.js +++ /dev/null @@ -1,679 +0,0 @@ -// Scrolling seems wonky, so I disabled checking to see if -// an element is in view before clicking or checking with -// { force: true } - -context('Tubes and Block', () => { - describe('96 Well', () => { - describe('Tubes', () => { - before(() => { - cy.visit('/create') - cy.viewport('macbook-15') - cy.contains('NO').click({ force: true }) - - // TODO(IL, 2021-05-15): give Dropdown component semantic selectors for E2E - cy.get('label') - .contains('What type of labware are you creating?') - .children() - .first() - .trigger('mousedown') - cy.get('*[class^="_option_label"]') - .contains('Tubes / Plates + Opentrons Aluminum Block') - .click() - - // TODO(IL, 2021-05-15): give Dropdown component semantic selectors for E2E - cy.get('label') - .contains('Which aluminum block?') - .children() - .first() - .trigger('mousedown') - cy.get('*[class^="_option_label"]').contains('96 well').click() - - // TODO(IL, 2021-05-15): give Dropdown component semantic selectors for E2E - cy.get('label') - .contains('What labware is on top of your aluminum block?') - .children() - .first() - .trigger('mousedown') - cy.get('*[class^="_option_label"]') - .contains(/^Tubes$/) - .click() - - cy.contains('start creating labware').click({ force: true }) - }) - - it('does not have a preview image', () => { - cy.contains('Add missing info to see labware preview').should('exist') - }) - - it('tests regularity', () => { - cy.get("input[name='homogeneousWells'][value='false']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('exist') - cy.get("input[name='homogeneousWells'][value='true']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('not.exist') - }) - - it('tests height', () => { - cy.get("input[name='labwareZDimension']").type('150').blur() - cy.contains('This labware may be too tall').should('exist') - cy.get("input[name='labwareZDimension']").clear().type('200').blur() - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('exist') - cy.get("input[name='labwareZDimension']").clear().type('75').blur() - cy.contains('This labware may be too tall').should('not.exist') - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('not.exist') - }) - - it('tests volume', () => { - cy.get("input[name='wellVolume']").focus().blur() - cy.contains('Volume is a required field').should('exist') - cy.get("input[name='wellVolume']").type('10').blur() - cy.contains('Volume is a required field').should('not.exist') - }) - - describe('Well shape tests', () => { - it('tests circular wells', () => { - cy.get("input[name='wellShape'][value='circular']").check({ - force: true, - }) - cy.get("input[name='wellDiameter']").should('exist') - cy.get("input[name='wellXDimension']").should('not.exist') - cy.get("input[name='wellYDimension']").should('not.exist') - cy.get("input[name='wellDiameter']").focus().blur() - cy.contains('Diameter is a required field').should('exist') - cy.get("input[name='wellDiameter']").type('10').blur() - cy.contains('Diameter is a required field').should('not.exist') - }) - - it('tests rectangular wells', () => { - cy.get("input[name='wellShape'][value='rectangular']").check({ - force: true, - }) - cy.get("input[name='wellDiameter']").should('not.exist') - cy.get("input[name='wellXDimension']").should('exist') - cy.get("input[name='wellYDimension']").should('exist') - cy.get("input[name='wellXDimension']").focus().blur() - cy.contains('Tube X is a required field').should('exist') - cy.get("input[name='wellXDimension']").type('10').blur() - cy.contains('Tube X is a required field').should('not.exist') - cy.get("input[name='wellYDimension']").focus().blur() - cy.contains('Tube Y is a required field').should('exist') - cy.get("input[name='wellYDimension']").type('10').blur() - cy.contains('Tube Y is a required field').should('not.exist') - }) - - it('tests well bottom shape and depth', () => { - cy.get("input[name='wellBottomShape'][value='flat']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('exist') - cy.get("img[src*='_round.']").should('not.exist') - cy.get("img[src*='_v.']").should('not.exist') - cy.get("input[name='wellBottomShape'][value='u']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('not.exist') - cy.get("img[src*='_round.']").should('exist') - cy.get("img[src*='_v.']").should('not.exist') - cy.get("input[name='wellBottomShape'][value='v']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('not.exist') - cy.get("img[src*='_round.']").should('not.exist') - cy.get("img[src*='_v.']").should('exist') - cy.get("input[name='wellDepth']").focus().blur() - cy.contains('Depth is a required field').should('exist') - cy.get("input[name='wellDepth']").type('10').blur() - cy.contains('Depth is a required field').should('not.exist') - }) - - it('does has a preview image', () => { - cy.contains('Add missing info to see labware preview').should( - 'not.exist' - ) - }) - - it('tests the file export', () => { - // Try with missing fields - cy.get('button[class*="_export_button_"]').click({ force: true }) - cy.contains( - 'Please resolve all invalid fields in order to export the labware definition' - ).should('exist') - cy.contains('close').click({ force: true }) - - // Brand info - cy.contains('Brand is a required field').should('exist') - cy.get("input[name='brand']").type('TestPro') - cy.contains('Brand is a required field').should('not.exist') - cy.get("input[name='brandId']").type('001') - - // File info - cy.get("input[placeholder='TestPro 96 Aluminum Block 10 µL']").should( - 'exist' - ) - cy.get("input[placeholder='testpro_96_aluminumblock_10ul']").should( - 'exist' - ) - - // All fields present - cy.get('button[class*="_export_button_"]').click({ force: true }) - cy.contains( - 'Please resolve all invalid fields in order to export the labware definition' - ).should('not.exist') - }) - }) - }) - - describe('PCR Tube Strip', () => { - before(() => { - cy.visit('/create') - cy.viewport('macbook-15') - cy.contains('NO').click({ force: true }) - - // TODO(IL, 2021-05-15): give Dropdown component semantic selectors for E2E - cy.get('label') - .contains('What type of labware are you creating?') - .children() - .first() - .trigger('mousedown') - cy.get('*[class^="_option_label"]') - .contains('Tubes / Plates + Opentrons Aluminum Block') - .click() - - // TODO(IL, 2021-05-15): give Dropdown component semantic selectors for E2E - cy.get('label') - .contains('Which aluminum block?') - .children() - .first() - .trigger('mousedown') - cy.get('*[class^="_option_label"]').contains('96 well').click() - - // TODO(IL, 2021-05-15): give Dropdown component semantic selectors for E2E - cy.get('label') - .contains('What labware is on top of your aluminum block?') - .children() - .first() - .trigger('mousedown') - cy.get('*[class^="_option_label"]').contains('PCR Tube Strip').click() - - cy.contains('start creating labware').click({ force: true }) - }) - - it('does not have a preview image', () => { - cy.contains('Add missing info to see labware preview').should('exist') - }) - - it('tests regularity', () => { - cy.get("input[name='homogeneousWells'][value='false']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('exist') - cy.get("input[name='homogeneousWells'][value='true']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('not.exist') - }) - - it('tests height', () => { - cy.get("input[name='labwareZDimension']").type('150').blur() - cy.contains('This labware may be too tall').should('exist') - cy.get("input[name='labwareZDimension']").clear().type('200').blur() - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('exist') - cy.get("input[name='labwareZDimension']").clear().type('75').blur() - cy.contains('This labware may be too tall').should('not.exist') - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('not.exist') - }) - - it('tests volume', () => { - cy.get("input[name='wellVolume']").focus().blur() - cy.contains('Volume is a required field').should('exist') - cy.get("input[name='wellVolume']").type('10').blur() - cy.contains('Volume is a required field').should('not.exist') - }) - - describe('Well shape tests', () => { - it('tests circular wells', () => { - cy.get("input[name='wellShape'][value='circular']").check({ - force: true, - }) - cy.get("input[name='wellDiameter']").should('exist') - cy.get("input[name='wellXDimension']").should('not.exist') - cy.get("input[name='wellYDimension']").should('not.exist') - cy.get("input[name='wellDiameter']").focus().blur() - cy.contains('Diameter is a required field').should('exist') - cy.get("input[name='wellDiameter']").type('10').blur() - cy.contains('Diameter is a required field').should('not.exist') - }) - - it('tests rectangular wells', () => { - cy.get("input[name='wellShape'][value='rectangular']").check({ - force: true, - }) - cy.get("input[name='wellDiameter']").should('not.exist') - cy.get("input[name='wellXDimension']").should('exist') - cy.get("input[name='wellYDimension']").should('exist') - cy.get("input[name='wellXDimension']").focus().blur() - cy.contains('Tube X is a required field').should('exist') - cy.get("input[name='wellXDimension']").type('10').blur() - cy.contains('Tube X is a required field').should('not.exist') - cy.get("input[name='wellYDimension']").focus().blur() - cy.contains('Tube Y is a required field').should('exist') - cy.get("input[name='wellYDimension']").type('10').blur() - cy.contains('Tube Y is a required field').should('not.exist') - }) - - it('tests well bottom shape and depth', () => { - cy.get("input[name='wellBottomShape'][value='flat']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('exist') - cy.get("img[src*='_round.']").should('not.exist') - cy.get("img[src*='_v.']").should('not.exist') - cy.get("input[name='wellBottomShape'][value='u']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('not.exist') - cy.get("img[src*='_round.']").should('exist') - cy.get("img[src*='_v.']").should('not.exist') - cy.get("input[name='wellBottomShape'][value='v']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('not.exist') - cy.get("img[src*='_round.']").should('not.exist') - cy.get("img[src*='_v.']").should('exist') - cy.get("input[name='wellDepth']").focus().blur() - cy.contains('Depth is a required field').should('exist') - cy.get("input[name='wellDepth']").type('10').blur() - cy.contains('Depth is a required field').should('not.exist') - }) - - it('does has a preview image', () => { - cy.contains('Add missing info to see labware preview').should( - 'not.exist' - ) - }) - - it('tests the file export', () => { - // Try with missing fields - cy.get('button[class*="_export_button_"]').click({ force: true }) - cy.contains( - 'Please resolve all invalid fields in order to export the labware definition' - ).should('exist') - cy.contains('close').click({ force: true }) - - // Brand info - cy.contains('Brand is a required field').should('exist') - cy.get("input[name='brand']").type('TestPro') - cy.contains('Brand is a required field').should('not.exist') - cy.get("input[name='brandId']").type('001') - - // File info - cy.get("input[placeholder='TestPro 96 Aluminum Block 10 µL']").should( - 'exist' - ) - cy.get("input[placeholder='testpro_96_aluminumblock_10ul']").should( - 'exist' - ) - - // All fields present - cy.get('button[class*="_export_button_"]').click({ force: true }) - cy.contains( - 'Please resolve all invalid fields in order to export the labware definition' - ).should('not.exist') - }) - }) - }) - - describe('PCR Plate', () => { - before(() => { - cy.visit('/create') - cy.viewport('macbook-15') - cy.contains('NO').click({ force: true }) - - // TODO(IL, 2021-05-15): give Dropdown component semantic selectors for E2E - cy.get('label') - .contains('What type of labware are you creating?') - .children() - .first() - .trigger('mousedown') - cy.get('*[class^="_option_label"]') - .contains('Tubes / Plates + Opentrons Aluminum Block') - .click() - - // TODO(IL, 2021-05-15): give Dropdown component semantic selectors for E2E - cy.get('label') - .contains('Which aluminum block?') - .children() - .first() - .trigger('mousedown') - cy.get('*[class^="_option_label"]').contains('96 well').click() - - // TODO(IL, 2021-05-15): give Dropdown component semantic selectors for E2E - cy.get('label') - .contains('What labware is on top of your aluminum block?') - .children() - .first() - .trigger('mousedown') - cy.get('*[class^="_option_label"]').contains('PCR Plate').click() - - cy.contains('start creating labware').click({ force: true }) - }) - - it('does not have a preview image', () => { - cy.contains('Add missing info to see labware preview').should('exist') - }) - - it('tests regularity', () => { - cy.get("input[name='homogeneousWells'][value='false']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('exist') - cy.get("input[name='homogeneousWells'][value='true']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('not.exist') - }) - - it('tests height', () => { - cy.get("input[name='labwareZDimension']").type('150').blur() - cy.contains('This labware may be too tall').should('exist') - cy.get("input[name='labwareZDimension']").clear().type('200').blur() - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('exist') - cy.get("input[name='labwareZDimension']").clear().type('75').blur() - cy.contains('This labware may be too tall').should('not.exist') - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('not.exist') - }) - - it('tests volume', () => { - cy.get("input[name='wellVolume']").focus().blur() - cy.contains('Volume is a required field').should('exist') - cy.get("input[name='wellVolume']").type('10').blur() - cy.contains('Volume is a required field').should('not.exist') - }) - - describe('Well shape tests', () => { - it('tests circular wells', () => { - cy.get("input[name='wellShape'][value='circular']").check({ - force: true, - }) - cy.get("input[name='wellDiameter']").should('exist') - cy.get("input[name='wellXDimension']").should('not.exist') - cy.get("input[name='wellYDimension']").should('not.exist') - cy.get("input[name='wellDiameter']").focus().blur() - cy.contains('Diameter is a required field').should('exist') - cy.get("input[name='wellDiameter']").type('10').blur() - cy.contains('Diameter is a required field').should('not.exist') - }) - - it('tests rectangular wells', () => { - cy.get("input[name='wellShape'][value='rectangular']").check({ - force: true, - }) - cy.get("input[name='wellDiameter']").should('not.exist') - cy.get("input[name='wellXDimension']").should('exist') - cy.get("input[name='wellYDimension']").should('exist') - cy.get("input[name='wellXDimension']").focus().blur() - cy.contains('Well X is a required field').should('exist') - cy.get("input[name='wellXDimension']").type('10').blur() - cy.contains('Well X is a required field').should('not.exist') - cy.get("input[name='wellYDimension']").focus().blur() - cy.contains('Well Y is a required field').should('exist') - cy.get("input[name='wellYDimension']").type('10').blur() - cy.contains('Well Y is a required field').should('not.exist') - }) - - it('tests well bottom shape and depth', () => { - cy.get("input[name='wellBottomShape'][value='flat']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('exist') - cy.get("img[src*='_round.']").should('not.exist') - cy.get("img[src*='_v.']").should('not.exist') - cy.get("input[name='wellBottomShape'][value='u']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('not.exist') - cy.get("img[src*='_round.']").should('exist') - cy.get("img[src*='_v.']").should('not.exist') - cy.get("input[name='wellBottomShape'][value='v']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('not.exist') - cy.get("img[src*='_round.']").should('not.exist') - cy.get("img[src*='_v.']").should('exist') - cy.get("input[name='wellDepth']").focus().blur() - cy.contains('Depth is a required field').should('exist') - cy.get("input[name='wellDepth']").type('10').blur() - cy.contains('Depth is a required field').should('not.exist') - }) - - it('does has a preview image', () => { - cy.contains('Add missing info to see labware preview').should( - 'not.exist' - ) - }) - - it('tests the file export', () => { - // Try with missing fields - cy.get('button[class*="_export_button_"]').click({ force: true }) - cy.contains( - 'Please resolve all invalid fields in order to export the labware definition' - ).should('exist') - cy.contains('close').click({ force: true }) - - // Brand info - cy.contains('Brand is a required field').should('exist') - cy.get("input[name='brand']").type('TestPro') - cy.contains('Brand is a required field').should('not.exist') - cy.get("input[name='brandId']").type('001') - - // File info - cy.get("input[placeholder='TestPro 96 Aluminum Block 10 µL']").should( - 'exist' - ) - cy.get("input[placeholder='testpro_96_aluminumblock_10ul']").should( - 'exist' - ) - - // All fields present - cy.get('button[class*="_export_button_"]').click({ force: true }) - cy.contains( - 'Please resolve all invalid fields in order to export the labware definition' - ).should('not.exist') - }) - }) - }) - }) - - describe('24 Well', () => { - describe('Tubes', () => { - before(() => { - cy.visit('/create') - cy.viewport('macbook-15') - cy.contains('NO').click({ force: true }) - - // TODO(IL, 2021-05-15): give Dropdown component semantic selectors for E2E - cy.get('label') - .contains('What type of labware are you creating?') - .children() - .first() - .trigger('mousedown') - cy.get('*[class^="_option_label"]') - .contains('Tubes / Plates + Opentrons Aluminum Block') - .click() - - // TODO(IL, 2021-05-15): give Dropdown component semantic selectors for E2E - cy.get('label') - .contains('Which aluminum block?') - .children() - .first() - .trigger('mousedown') - cy.get('*[class^="_option_label"]').contains('24 well').click() - - cy.get('label') - .contains('What labware is on top of your aluminum block?') - .should('not.exist') - - cy.contains('start creating labware').click({ force: true }) - }) - - it('does not have a preview image', () => { - cy.contains('Add missing info to see labware preview').should('exist') - }) - - it('tests regularity', () => { - cy.get("input[name='homogeneousWells'][value='false']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('exist') - cy.get("input[name='homogeneousWells'][value='true']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('not.exist') - }) - - it('tests height', () => { - cy.get("input[name='labwareZDimension']").type('150').blur() - cy.contains('This labware may be too tall').should('exist') - cy.get("input[name='labwareZDimension']").clear().type('200').blur() - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('exist') - cy.get("input[name='labwareZDimension']").clear().type('75').blur() - cy.contains('This labware may be too tall').should('not.exist') - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('not.exist') - }) - - it('tests volume', () => { - cy.get("input[name='wellVolume']").focus().blur() - cy.contains('Volume is a required field').should('exist') - cy.get("input[name='wellVolume']").type('10').blur() - cy.contains('Volume is a required field').should('not.exist') - }) - - describe('Well shape tests', () => { - it('tests circular wells', () => { - cy.get("input[name='wellShape'][value='circular']").check({ - force: true, - }) - cy.get("input[name='wellDiameter']").should('exist') - cy.get("input[name='wellXDimension']").should('not.exist') - cy.get("input[name='wellYDimension']").should('not.exist') - cy.get("input[name='wellDiameter']").focus().blur() - cy.contains('Diameter is a required field').should('exist') - cy.get("input[name='wellDiameter']").type('10').blur() - cy.contains('Diameter is a required field').should('not.exist') - }) - - it('tests rectangular wells', () => { - cy.get("input[name='wellShape'][value='rectangular']").check({ - force: true, - }) - cy.get("input[name='wellDiameter']").should('not.exist') - cy.get("input[name='wellXDimension']").should('exist') - cy.get("input[name='wellYDimension']").should('exist') - cy.get("input[name='wellXDimension']").focus().blur() - cy.contains('Well X is a required field').should('exist') - cy.get("input[name='wellXDimension']").type('10').blur() - cy.contains('Well X is a required field').should('not.exist') - cy.get("input[name='wellYDimension']").focus().blur() - cy.contains('Well Y is a required field').should('exist') - cy.get("input[name='wellYDimension']").type('10').blur() - cy.contains('Well Y is a required field').should('not.exist') - }) - - it('tests well bottom shape and depth', () => { - cy.get("input[name='wellBottomShape'][value='flat']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('exist') - cy.get("img[src*='_round.']").should('not.exist') - cy.get("img[src*='_v.']").should('not.exist') - cy.get("input[name='wellBottomShape'][value='u']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('not.exist') - cy.get("img[src*='_round.']").should('exist') - cy.get("img[src*='_v.']").should('not.exist') - cy.get("input[name='wellBottomShape'][value='v']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('not.exist') - cy.get("img[src*='_round.']").should('not.exist') - cy.get("img[src*='_v.']").should('exist') - cy.get("input[name='wellDepth']").focus().blur() - cy.contains('Depth is a required field').should('exist') - cy.get("input[name='wellDepth']").type('10').blur() - cy.contains('Depth is a required field').should('not.exist') - }) - - it('does has a preview image', () => { - cy.contains('Add missing info to see labware preview').should( - 'not.exist' - ) - }) - - it('tests the file export', () => { - // Try with missing fields - cy.get('button[class*="_export_button_"]').click({ force: true }) - cy.contains( - 'Please resolve all invalid fields in order to export the labware definition' - ).should('exist') - cy.contains('close').click({ force: true }) - - // Brand info - cy.contains('Brand is a required field').should('exist') - cy.get("input[name='brand']").type('TestPro') - cy.contains('Brand is a required field').should('not.exist') - cy.get("input[name='brandId']").type('001') - - // File info - cy.get("input[placeholder='TestPro 24 Aluminum Block 10 µL']").should( - 'exist' - ) - cy.get("input[placeholder='testpro_24_aluminumblock_10ul']").should( - 'exist' - ) - - // All fields present - cy.get('button[class*="_export_button_"]').click({ force: true }) - cy.contains( - 'Please resolve all invalid fields in order to export the labware definition' - ).should('not.exist') - }) - }) - }) - }) -}) diff --git a/labware-library/cypress/integration/labware-creator/tubesRack.spec.js b/labware-library/cypress/integration/labware-creator/tubesRack.spec.js deleted file mode 100644 index 3ea956a9bae..00000000000 --- a/labware-library/cypress/integration/labware-creator/tubesRack.spec.js +++ /dev/null @@ -1,446 +0,0 @@ -// Scrolling seems wonky, so I disabled checking to see if -// an element is in view before clicking or checking with -// { force: true } - -context('Tubes and Rack', () => { - describe('Six tubes', () => { - before(() => { - cy.visit('/create') - cy.viewport('macbook-15') - cy.contains('NO').click({ force: true }) - // TODO(IL, 2021-05-15): give Dropdown component semantic selectors for E2E - cy.get('label') - .contains('What type of labware are you creating?') - .children() - .first() - .trigger('mousedown') - cy.get('*[class^="_option_label"]').contains('Tubes + Tube Rack').click() - - // TODO(IL, 2021-05-15): give Dropdown component semantic selectors for E2E - cy.get('label') - .contains('Which tube rack?') - .children() - .first() - .trigger('mousedown') - cy.get('*[class^="_option_label"]').contains('6 tubes').click() - - cy.contains('start creating labware').click({ force: true }) - }) - - it('does not have a preview image', () => { - cy.contains('Add missing info to see labware preview').should('exist') - }) - - it('tests regularity', () => { - cy.get("input[name='homogeneousWells'][value='false']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('exist') - cy.get("input[name='homogeneousWells'][value='true']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('not.exist') - }) - - it('tests height', () => { - cy.get("input[name='labwareZDimension']").type('150').blur() - cy.contains('This labware may be too tall').should('exist') - cy.get("input[name='labwareZDimension']").clear().type('200').blur() - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('exist') - cy.get("input[name='labwareZDimension']").clear().type('75').blur() - cy.contains('This labware may be too tall').should('not.exist') - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('not.exist') - }) - - it('tests volume', () => { - cy.get("input[name='wellVolume']").focus().blur() - cy.contains('Volume is a required field').should('exist') - cy.get("input[name='wellVolume']").type('10').blur() - cy.contains('Volume is a required field').should('not.exist') - }) - - describe('Well shape tests', () => { - it('tests circular wells', () => { - cy.get("input[name='wellShape'][value='circular']").check({ - force: true, - }) - cy.get("input[name='wellDiameter']").should('exist') - cy.get("input[name='wellXDimension']").should('not.exist') - cy.get("input[name='wellYDimension']").should('not.exist') - cy.get("input[name='wellDiameter']").focus().blur() - cy.contains('Diameter is a required field').should('exist') - cy.get("input[name='wellDiameter']").type('10').blur() - cy.contains('Diameter is a required field').should('not.exist') - }) - - it('tests rectangular wells', () => { - cy.get("input[name='wellShape'][value='rectangular']").check({ - force: true, - }) - cy.get("input[name='wellDiameter']").should('not.exist') - cy.get("input[name='wellXDimension']").should('exist') - cy.get("input[name='wellYDimension']").should('exist') - cy.get("input[name='wellXDimension']").focus().blur() - cy.contains('Tube X is a required field').should('exist') - cy.get("input[name='wellXDimension']").type('10').blur() - cy.contains('Tube X is a required field').should('not.exist') - cy.get("input[name='wellYDimension']").focus().blur() - cy.contains('Tube Y is a required field').should('exist') - cy.get("input[name='wellYDimension']").type('10').blur() - cy.contains('Tube Y is a required field').should('not.exist') - }) - - it('tests well bottom shape and depth', () => { - cy.get("input[name='wellBottomShape'][value='flat']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('exist') - cy.get("img[src*='_round.']").should('not.exist') - cy.get("img[src*='_v.']").should('not.exist') - cy.get("input[name='wellBottomShape'][value='u']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('not.exist') - cy.get("img[src*='_round.']").should('exist') - cy.get("img[src*='_v.']").should('not.exist') - cy.get("input[name='wellBottomShape'][value='v']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('not.exist') - cy.get("img[src*='_round.']").should('not.exist') - cy.get("img[src*='_v.']").should('exist') - cy.get("input[name='wellDepth']").focus().blur() - cy.contains('Depth is a required field').should('exist') - cy.get("input[name='wellDepth']").type('10').blur() - cy.contains('Depth is a required field').should('not.exist') - }) - - it('does has a preview image', () => { - cy.contains('Add missing info to see labware preview').should( - 'not.exist' - ) - }) - - it('tests the file export', () => { - // Brand field should not be shown for Opentrons tube rack (aka non-custom) - cy.contains('Brand is a required field').should('not.exist') - - // File info - cy.get( - "input[placeholder='Opentrons 6 Tube Rack with Generic 0.01 mL']" - ).should('exist') - cy.get("input[placeholder='opentrons_6_tuberack_10ul']").should('exist') - - // All fields present - cy.get('button[class*="_export_button_"]').click({ force: true }) - cy.contains( - 'Please resolve all invalid fields in order to export the labware definition' - ).should('not.exist') - }) - }) - }) - - describe('Fifteen tubes', () => { - before(() => { - cy.visit('/create') - cy.viewport('macbook-15') - cy.contains('NO').click({ force: true }) - - // TODO(IL, 2021-05-15): give Dropdown component semantic selectors for E2E - cy.get('label') - .contains('What type of labware are you creating?') - .children() - .first() - .trigger('mousedown') - cy.get('*[class^="_option_label"]').contains('Tubes + Tube Rack').click() - - // TODO(IL, 2021-05-15): give Dropdown component semantic selectors for E2E - cy.get('label') - .contains('Which tube rack?') - .children() - .first() - .trigger('mousedown') - cy.get('*[class^="_option_label"]').contains('15 tubes').click() - - cy.contains('start creating labware').click({ force: true }) - }) - - it('does not have a preview image', () => { - cy.contains('Add missing info to see labware preview').should('exist') - }) - - it('tests regularity', () => { - cy.get("input[name='homogeneousWells'][value='false']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('exist') - cy.get("input[name='homogeneousWells'][value='true']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('not.exist') - }) - - it('tests height', () => { - cy.get("input[name='labwareZDimension']").type('150').blur() - cy.contains('This labware may be too tall').should('exist') - cy.get("input[name='labwareZDimension']").clear().type('200').blur() - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('exist') - cy.get("input[name='labwareZDimension']").clear().type('75').blur() - cy.contains('This labware may be too tall').should('not.exist') - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('not.exist') - }) - - it('tests volume', () => { - cy.get("input[name='wellVolume']").focus().blur() - cy.contains('Volume is a required field').should('exist') - cy.get("input[name='wellVolume']").type('10').blur() - cy.contains('Volume is a required field').should('not.exist') - }) - - describe('Well shape tests', () => { - it('tests circular wells', () => { - cy.get("input[name='wellShape'][value='circular']").check({ - force: true, - }) - cy.get("input[name='wellDiameter']").should('exist') - cy.get("input[name='wellXDimension']").should('not.exist') - cy.get("input[name='wellYDimension']").should('not.exist') - cy.get("input[name='wellDiameter']").focus().blur() - cy.contains('Diameter is a required field').should('exist') - cy.get("input[name='wellDiameter']").type('10').blur() - cy.contains('Diameter is a required field').should('not.exist') - }) - - it('tests rectangular wells', () => { - cy.get("input[name='wellShape'][value='rectangular']").check({ - force: true, - }) - cy.get("input[name='wellDiameter']").should('not.exist') - cy.get("input[name='wellXDimension']").should('exist') - cy.get("input[name='wellYDimension']").should('exist') - cy.get("input[name='wellXDimension']").focus().blur() - cy.contains('Tube X is a required field').should('exist') - cy.get("input[name='wellXDimension']").type('10').blur() - cy.contains('Tube X is a required field').should('not.exist') - cy.get("input[name='wellYDimension']").focus().blur() - cy.contains('Tube Y is a required field').should('exist') - cy.get("input[name='wellYDimension']").type('10').blur() - cy.contains('Tube Y is a required field').should('not.exist') - }) - - it('tests well bottom shape and depth', () => { - cy.get("input[name='wellBottomShape'][value='flat']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('exist') - cy.get("img[src*='_round.']").should('not.exist') - cy.get("img[src*='_v.']").should('not.exist') - cy.get("input[name='wellBottomShape'][value='u']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('not.exist') - cy.get("img[src*='_round.']").should('exist') - cy.get("img[src*='_v.']").should('not.exist') - cy.get("input[name='wellBottomShape'][value='v']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('not.exist') - cy.get("img[src*='_round.']").should('not.exist') - cy.get("img[src*='_v.']").should('exist') - cy.get("input[name='wellDepth']").focus().blur() - cy.contains('Depth is a required field').should('exist') - cy.get("input[name='wellDepth']").type('10').blur() - cy.contains('Depth is a required field').should('not.exist') - }) - - it('does has a preview image', () => { - cy.contains('Add missing info to see labware preview').should( - 'not.exist' - ) - }) - - it('tests the file export', () => { - // Brand field should not be shown for Opentrons tube rack (aka non-custom) - cy.contains('Brand is a required field').should('not.exist') - - // File info - cy.get( - "input[placeholder='Opentrons 15 Tube Rack with Generic 0.01 mL']" - ).should('exist') - cy.get("input[placeholder='opentrons_15_tuberack_10ul']").should( - 'exist' - ) - - // All fields present - cy.get('button[class*="_export_button_"]').click({ force: true }) - cy.contains( - 'Please resolve all invalid fields in order to export the labware definition' - ).should('not.exist') - }) - }) - }) - - describe('Twentyfour tubes', () => { - before(() => { - cy.visit('/create') - cy.viewport('macbook-15') - cy.contains('NO').click({ force: true }) - - // TODO(IL, 2021-05-15): give Dropdown component semantic selectors for E2E - cy.get('label') - .contains('What type of labware are you creating?') - .children() - .first() - .trigger('mousedown') - cy.get('*[class^="_option_label"]').contains('Tubes + Tube Rack').click() - - // TODO(IL, 2021-05-15): give Dropdown component semantic selectors for E2E - cy.get('label') - .contains('Which tube rack?') - .children() - .first() - .trigger('mousedown') - cy.get('*[class^="_option_label"]').contains('24 tubes').click() - - cy.contains('start creating labware').click({ force: true }) - }) - - it('does not have a preview image', () => { - cy.contains('Add missing info to see labware preview').should('exist') - }) - - it('tests regularity', () => { - cy.get("input[name='homogeneousWells'][value='false']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('exist') - cy.get("input[name='homogeneousWells'][value='true']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('not.exist') - }) - - it('tests height', () => { - cy.get("input[name='labwareZDimension']").type('150').blur() - cy.contains('This labware may be too tall').should('exist') - cy.get("input[name='labwareZDimension']").clear().type('200').blur() - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('exist') - cy.get("input[name='labwareZDimension']").clear().type('75').blur() - cy.contains('This labware may be too tall').should('not.exist') - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('not.exist') - }) - - it('tests volume', () => { - cy.get("input[name='wellVolume']").focus().blur() - cy.contains('Volume is a required field').should('exist') - cy.get("input[name='wellVolume']").type('10').blur() - cy.contains('Volume is a required field').should('not.exist') - }) - - describe('Well shape tests', () => { - it('tests circular wells', () => { - cy.get("input[name='wellShape'][value='circular']").check({ - force: true, - }) - cy.get("input[name='wellDiameter']").should('exist') - cy.get("input[name='wellXDimension']").should('not.exist') - cy.get("input[name='wellYDimension']").should('not.exist') - cy.get("input[name='wellDiameter']").focus().blur() - cy.contains('Diameter is a required field').should('exist') - cy.get("input[name='wellDiameter']").type('10').blur() - cy.contains('Diameter is a required field').should('not.exist') - }) - - it('tests rectangular wells', () => { - cy.get("input[name='wellShape'][value='rectangular']").check({ - force: true, - }) - cy.get("input[name='wellDiameter']").should('not.exist') - cy.get("input[name='wellXDimension']").should('exist') - cy.get("input[name='wellYDimension']").should('exist') - cy.get("input[name='wellXDimension']").focus().blur() - cy.contains('Tube X is a required field').should('exist') - cy.get("input[name='wellXDimension']").type('10').blur() - cy.contains('Tube X is a required field').should('not.exist') - cy.get("input[name='wellYDimension']").focus().blur() - cy.contains('Tube Y is a required field').should('exist') - cy.get("input[name='wellYDimension']").type('10').blur() - cy.contains('Tube Y is a required field').should('not.exist') - }) - - it('tests well bottom shape and depth', () => { - cy.get("input[name='wellBottomShape'][value='flat']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('exist') - cy.get("img[src*='_round.']").should('not.exist') - cy.get("img[src*='_v.']").should('not.exist') - cy.get("input[name='wellBottomShape'][value='u']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('not.exist') - cy.get("img[src*='_round.']").should('exist') - cy.get("img[src*='_v.']").should('not.exist') - cy.get("input[name='wellBottomShape'][value='v']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('not.exist') - cy.get("img[src*='_round.']").should('not.exist') - cy.get("img[src*='_v.']").should('exist') - cy.get("input[name='wellDepth']").focus().blur() - cy.contains('Depth is a required field').should('exist') - cy.get("input[name='wellDepth']").type('10').blur() - cy.contains('Depth is a required field').should('not.exist') - }) - - it('does has a preview image', () => { - cy.contains('Add missing info to see labware preview').should( - 'not.exist' - ) - }) - - it('tests the file export', () => { - // Brand field should not be shown for Opentrons tube rack (aka non-custom) - cy.contains('Brand is a required field').should('not.exist') - - // File info - cy.get( - "input[placeholder='Opentrons 24 Tube Rack with Generic 0.01 mL']" - ).should('exist') - cy.get("input[placeholder='opentrons_24_tuberack_10ul']").should( - 'exist' - ) - - // All fields present - cy.get('button[class*="_export_button_"]').click({ force: true }) - cy.contains( - 'Please resolve all invalid fields in order to export the labware definition' - ).should('not.exist') - }) - }) - }) -}) diff --git a/labware-library/cypress/integration/labware-creator/wellPlate.spec.js b/labware-library/cypress/integration/labware-creator/wellPlate.spec.js deleted file mode 100644 index 0a32a628e34..00000000000 --- a/labware-library/cypress/integration/labware-creator/wellPlate.spec.js +++ /dev/null @@ -1,249 +0,0 @@ -// NOTE: This uses data that produces a labware definition file -// that cannot be imported. The creator probably shouldn't allow -// a user to do this. - -// Scrolling seems wonky, so I disabled checking to see if -// an element is in view before clicking or checking with -// { force: true } - -context('Well Plates', () => { - before(() => { - cy.visit('/create') - cy.viewport('macbook-15') - cy.contains('NO').click({ force: true }) - }) - - describe('Create a well plate', () => { - before(() => { - // TODO(IL, 2021-05-15): give Dropdown component semantic selectors for E2E - cy.get('label') - .contains('What type of labware are you creating?') - .children() - .first() - .trigger('mousedown') - cy.get('*[class^="_option_label"]').contains('Well Plate').click() - cy.get('button').contains('start creating labware').click({ force: true }) - }) - - it('does not have a preview image', () => { - cy.contains('Add missing info to see labware preview').should('exist') - }) - - it('tests regularity', () => { - cy.get("input[name='homogeneousWells'][value='false']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('exist') - cy.get("input[name='homogeneousWells'][value='true']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('not.exist') - }) - - it('tests footprint', () => { - cy.get("input[name='footprintXDimension']").type('150').blur() - cy.contains( - 'Your labware is too large to fit in a single slot properly. Please fill out this form to request a custom labware definition.' - ).should('exist') - cy.get("input[name='footprintXDimension']").clear().type('127').blur() - cy.contains( - 'Your labware is too large to fit in a single slot properly. Please fill out this form to request a custom labware definition.' - ).should('not.exist') - cy.get("input[name='footprintYDimension']").type('150').blur() - cy.contains( - 'Your labware is too large to fit in a single slot properly. Please fill out this form to request a custom labware definition.' - ).should('exist') - cy.get("input[name='footprintYDimension']").clear().type('85').blur() - cy.contains( - 'Your labware is too large to fit in a single slot properly. Please fill out this form to request a custom labware definition.' - ).should('not.exist') - }) - - it('tests height', () => { - cy.get("input[name='labwareZDimension']").type('150').blur() - cy.contains('This labware may be too tall').should('exist') - cy.get("input[name='labwareZDimension']").clear().type('200').blur() - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('exist') - cy.get("input[name='labwareZDimension']").clear().type('75').blur() - cy.contains('This labware may be too tall').should('not.exist') - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('not.exist') - }) - - describe('Grid tests', () => { - it('tests number of rows', () => { - cy.get("input[name='gridRows']").focus().blur() - cy.contains('Number of rows is a required field').should('exist') - cy.get("input[name='gridRows']").type('8').blur() - cy.contains('Number of rows is a required field').should('not.exist') - }) - - it('tests are all of your rows evenly spaced', () => { - cy.get("input[name='regularRowSpacing'][value='false']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('exist') - cy.get("input[name='regularRowSpacing'][value='true']").check({ - force: true, - }) - }) - - it('tests number of columns', () => { - cy.get("input[name='gridColumns']").focus().blur() - cy.contains('Number of columns is a required field').should('exist') - cy.get("input[name='gridColumns']").type('10').blur() - cy.contains('Number of columns is a required field').should('not.exist') - }) - - it('tests are all of your columns evenly spaced', () => { - cy.get("input[name='regularColumnSpacing'][value='false']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('exist') - cy.get("input[name='regularColumnSpacing'][value='true']").check({ - force: true, - }) - cy.contains( - 'Your labware is not compatible with the Labware Creator' - ).should('not.exist') - }) - }) - - it('tests volume', () => { - cy.get("input[name='wellVolume']").focus().blur() - cy.contains('Volume is a required field').should('exist') - cy.get("input[name='wellVolume']").type('100').blur() - cy.contains('Volume is a required field').should('not.exist') - }) - - describe('Well shape tests', () => { - it('tests circular wells', () => { - cy.get("input[name='wellShape'][value='circular']").check({ - force: true, - }) - cy.get("input[name='wellDiameter']").should('exist') - cy.get("input[name='wellXDimension']").should('not.exist') - cy.get("input[name='wellYDimension']").should('not.exist') - cy.get("input[name='wellDiameter']").focus().blur() - cy.contains('Diameter is a required field').should('exist') - cy.get("input[name='wellDiameter']").type('10').blur() - cy.contains('Diameter is a required field').should('not.exist') - }) - - it('tests rectangular wells', () => { - cy.get("input[name='wellShape'][value='rectangular']").check({ - force: true, - }) - cy.get("input[name='wellDiameter']").should('not.exist') - cy.get("input[name='wellXDimension']").should('exist') - cy.get("input[name='wellYDimension']").should('exist') - cy.get("input[name='wellXDimension']").focus().blur() - cy.contains('Well X is a required field').should('exist') - cy.get("input[name='wellXDimension']").type('8').blur() - cy.contains('Well X is a required field').should('not.exist') - cy.get("input[name='wellYDimension']").focus().blur() - cy.contains('Well Y is a required field').should('exist') - cy.get("input[name='wellYDimension']").type('8').blur() - cy.contains('Well Y is a required field').should('not.exist') - }) - - it('tests well bottom shape and depth', () => { - cy.get("input[name='wellBottomShape'][value='flat']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('exist') - cy.get("img[src*='_round.']").should('not.exist') - cy.get("img[src*='_v.']").should('not.exist') - cy.get("input[name='wellBottomShape'][value='u']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('not.exist') - cy.get("img[src*='_round.']").should('exist') - cy.get("img[src*='_v.']").should('not.exist') - cy.get("input[name='wellBottomShape'][value='v']").check({ - force: true, - }) - cy.get("img[src*='_flat.']").should('not.exist') - cy.get("img[src*='_round.']").should('not.exist') - cy.get("img[src*='_v.']").should('exist') - cy.get("input[name='wellDepth']").focus().blur() - cy.contains('Depth is a required field').should('exist') - cy.get("input[name='wellDepth']").type('10').blur() - cy.contains('Depth is a required field').should('not.exist') - }) - - it('tests well spacing', () => { - cy.get("input[name='gridSpacingX']").focus().blur() - cy.contains('X Spacing (Xs) is a required field').should('exist') - cy.get("input[name='gridSpacingX']").type('12').blur() - cy.contains('X Spacing (Xs) is a required field').should('not.exist') - cy.get("input[name='gridSpacingY']").focus().blur() - cy.contains('Y Spacing (Ys) is a required field').should('exist') - cy.get("input[name='gridSpacingY']").type('10').blur() - cy.contains('Y Spacing (Ys) is a required field').should('not.exist') - }) - - it('tests grid offset', () => { - cy.get("input[name='gridOffsetX']").focus().blur() - cy.contains('X Offset (Xo) is a required field').should('exist') - cy.get("input[name='gridOffsetX']").type('10').blur() - cy.contains('X Offset (Xo) is a required field').should('not.exist') - cy.get("input[name='gridOffsetY']").focus().blur() - cy.contains('Y Offset (Yo) is a required field').should('exist') - cy.get("input[name='gridOffsetY']").type('8').blur() - cy.contains('Y Offset (Yo) is a required field').should('not.exist') - }) - - it('should have a preview image and no footprint errors', () => { - cy.contains('Add missing info to see labware preview').should( - 'not.exist' - ) - cy.contains( - 'Please double-check well size, Y Spacing, and Y Offset.' - ).should('not.exist') - }) - - it('should export a file', () => { - // Try with missing fields - cy.get('button[class*="_export_button_"]').click({ force: true }) - cy.contains( - 'Please resolve all invalid fields in order to export the labware definition' - ).should('exist') - cy.contains('close').click({ force: true }) - - // Brand info - cy.contains('Brand is a required field').should('exist') - cy.get("input[name='brand']").type('TestPro') - cy.contains('Brand is a required field').should('not.exist') - cy.get("input[name='brandId']").type('001') - - // File info - cy.get("input[placeholder='TestPro 80 Well Plate 100 µL']").should( - 'exist' - ) - cy.get("input[placeholder='testpro_80_wellplate_100ul']").should( - 'exist' - ) - - // All fields present - cy.get('button[class*="_export_button_"]').click({ force: true }) - cy.contains( - 'Please resolve all invalid fields in order to export the labware definition' - ).should('not.exist') - - // TODO IMMEDIATELY match against fixture ??? Is this not happening? - }) - }) - }) -}) diff --git a/labware-library/cypress/support/index.js b/labware-library/cypress/support/e2e.js similarity index 100% rename from labware-library/cypress/support/index.js rename to labware-library/cypress/support/e2e.js diff --git a/labware-library/vite.config.ts b/labware-library/vite.config.ts index 2db2bd80b1a..d21c3622266 100644 --- a/labware-library/vite.config.ts +++ b/labware-library/vite.config.ts @@ -64,4 +64,7 @@ export default defineConfig({ ...testAliases, }, }, + server: { + port: 5179, + }, }) diff --git a/labware-library/webpack.config.js b/labware-library/webpack.config.js deleted file mode 100644 index c5fb0d8c7e8..00000000000 --- a/labware-library/webpack.config.js +++ /dev/null @@ -1,67 +0,0 @@ -'use strict' -const path = require('path') -const webpack = require('webpack') -const merge = require('webpack-merge') -const HtmlWebpackPlugin = require('html-webpack-plugin') -// const glob = require('glob') - -const { baseConfig } = require('@opentrons/webpack-config') -// const {baseConfig, DEV_MODE} = require('@opentrons/webpack-config') -const pkg = require('./package.json') - -const { versionForProject } = require('../scripts/git-version') - -const JS_ENTRY = path.join(__dirname, 'src/index.tsx') -const HTML_ENTRY = path.join(__dirname, 'src/index.hbs') -const OUT_PATH = path.join(__dirname, 'dist') - -const LABWARE_LIBRARY_ENV_VAR_PREFIX = 'OT_LL' - -const passThruEnvVars = Object.keys(process.env) - .filter(v => v.startsWith(LABWARE_LIBRARY_ENV_VAR_PREFIX)) - .concat(['NODE_ENV', 'CYPRESS']) - -const testAliases = - process.env.CYPRESS === '1' - ? { - 'file-saver': path.resolve(__dirname, 'cypress/mocks/file-saver.js'), - } - : {} - -module.exports = async () => { - const envVarsWithDefaults = { - OT_LL_VERSION: await versionForProject('labware-library'), - OT_LL_BUILD_DATE: new Date().toUTCString(), - } - - const envVars = passThruEnvVars.reduce( - (acc, envVar) => ({ [envVar]: '', ...acc }), - { ...envVarsWithDefaults } - ) - - return merge(baseConfig, { - entry: JS_ENTRY, - - output: { - path: OUT_PATH, - publicPath: '/', - }, - - plugins: [ - new webpack.EnvironmentPlugin(envVars), - - new HtmlWebpackPlugin({ - template: HTML_ENTRY, - title: pkg.productName, - description: pkg.description, - author: pkg.author.name, - gtmId: process.env.GTM_ID, - favicon: './src/images/favicon.ico', - }), - ], - - resolve: { - alias: testAliases, - }, - }) -} diff --git a/opentrons-ai-client/Makefile b/opentrons-ai-client/Makefile new file mode 100644 index 00000000000..8afd804af4c --- /dev/null +++ b/opentrons-ai-client/Makefile @@ -0,0 +1,63 @@ +# opentrons ai client makefile + +# using bash instead of /bin/bash in SHELL prevents macOS optimizing away our PATH update +SHELL := bash + +# add node_modules/.bin to PATH +PATH := $(shell cd .. && yarn bin):$(PATH) + +# dev server port +PORT ?= 5173 + +benchmark_output := $(shell node -e 'console.log(new Date());') + +# These variables can be overriden when make is invoked to customize the +# behavior of jest +tests ?= +cov_opts ?= --coverage=true +test_opts ?= + +# standard targets +##################################################################### + +.PHONY: all +all: clean build + +.PHONY: setup +setup: + yarn + +.PHONY: clean +clean: + shx rm -rf dist + +# artifacts +##################################################################### + +.PHONY: build +build: export NODE_ENV := production +build: + vite build + git rev-parse HEAD > dist/.commit + +# development +##################################################################### + +.PHONY: dev +dev: export NODE_ENV := development +dev: export PORT := $(PORT) +dev: + vite serve + +# production assets server +.PHONY: serve +serve: all + node ../scripts/serve-static dist + +.PHONY: test +test: + $(MAKE) -C .. test-js-ai-client tests="$(tests)" test_opts="$(test_opts)" + +.PHONY: test-cov +test-cov: + make -C .. test-js-ai-client tests=$(tests) test_opts="$(test_opts)" cov_opts="$(cov_opts)" diff --git a/opentrons-ai-client/README.md b/opentrons-ai-client/README.md new file mode 100644 index 00000000000..d4c80c2bb23 --- /dev/null +++ b/opentrons-ai-client/README.md @@ -0,0 +1,63 @@ +# Opentrons AI Frontend + +[![JavaScript Style Guide][style-guide-badge]][style-guide] + +## Overview + +The Opentrons AI application helps you to create a protocol with natural language. + +## Developing + +To get started: clone the `Opentrons/opentrons` repository, set up your computer for development as specified in the [contributing guide][contributing-guide-setup], and then: + +```shell +# change into the cloned directory +cd opentrons +# prerequisite: install dependencies as specified in project setup +make setup +# launch the dev server +make -C opentrons-ai-client dev +``` + +## Stack and structure + +The UI stack is built using: + +- [React][] +- [Babel][] +- [Vite][] + +Some important directories: + +- [opentrons-ai-server][] — Opentrons AI application's server + +## Copy management + +We use [i18next](https://www.i18next.com) for copy management and internationalization. + +## Testing + +Tests for the Opentrons App are run from the top level along with all other JS project tests. + +- `make test-js` - Run all JavaScript tests + +Test tasks can also be run with the following arguments: + +| Argument | Default | Description | Example | +| -------- | -------- | ----------------------- | --------------------------------- | +| watch | `false` | Run tests in watch mode | `make test-unit watch=true` | +| cover | `!watch` | Calculate code coverage | `make test watch=true cover=true` | + +## Building + +TBD + +[style-guide]: https://standardjs.com +[style-guide-badge]: https://img.shields.io/badge/code_style-standard-brightgreen.svg?style=flat-square&maxAge=3600 +[contributing-guide-setup]: ../CONTRIBUTING.md#development-setup +[contributing-guide-running-the-api]: ../CONTRIBUTING.md#opentrons-api +[react]: https://react.dev/ +[babel]: https://babeljs.io/ +[vite]: https://vitejs.dev/ +[bundle-analyzer]: https://github.com/webpack-contrib/webpack-bundle-analyzer +[opentrons-ai-server]: https://github.com/Opentrons/opentrons/tree/edge/opentrons-ai-server diff --git a/opentrons-ai-client/babel.config.cjs b/opentrons-ai-client/babel.config.cjs new file mode 100644 index 00000000000..11739e6bf00 --- /dev/null +++ b/opentrons-ai-client/babel.config.cjs @@ -0,0 +1,21 @@ +'use strict' + +module.exports = { + env: { + // Must have babel-plugin-styled-components in each env, + // see here for further details: s https://styled-components.com/docs/tooling#babel-plugin + production: { + plugins: ['babel-plugin-styled-components', 'babel-plugin-unassert'], + }, + development: { + plugins: ['babel-plugin-styled-components'], + }, + test: { + plugins: [ + // disable ssr, displayName to fix toHaveStyleRule + // https://github.com/styled-components/jest-styled-components/issues/294 + ['babel-plugin-styled-components', { ssr: false, displayName: false }], + ], + }, + }, +} diff --git a/opentrons-ai-client/index.html b/opentrons-ai-client/index.html new file mode 100644 index 00000000000..4e8e60a4121 --- /dev/null +++ b/opentrons-ai-client/index.html @@ -0,0 +1,14 @@ + + + + + + + + Opentrons AI + + +
+ + + diff --git a/opentrons-ai-client/package.json b/opentrons-ai-client/package.json new file mode 100644 index 00000000000..dfd8069c7b1 --- /dev/null +++ b/opentrons-ai-client/package.json @@ -0,0 +1,41 @@ +{ + "name": "opentrons-ai-client", + "type": "module", + "version": "0.0.0-dev", + "description": "Opentrons AI application UI", + "source": "src/index.tsx", + "types": "lib/index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/Opentrons/opentrons.git" + }, + "author": { + "name": "Opentrons Labworks", + "email": "engineering@opentrons.com" + }, + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/Opentrons/opentrons/issues" + }, + "homepage": "https://github.com/Opentrons/opentrons", + "dependencies": { + "@fontsource/public-sans": "5.0.3", + "@opentrons/components": "link:../components", + "axios": "^0.21.1", + "i18next": "^19.8.3", + "jotai": "2.8.0", + "react": "18.2.0", + "react-dom": "18.2.0", + "react-error-boundary": "^4.0.10", + "react-hook-form": "7.50.1", + "react-i18next": "13.5.0", + "react-markdown": "9.0.1", + "styled-components": "5.3.6" + }, + "engines": { + "node": ">=18.19.0" + }, + "devDependencies": { + "@types/styled-components": "^5.1.26" + } +} diff --git a/opentrons-ai-client/src/App.test.tsx b/opentrons-ai-client/src/App.test.tsx new file mode 100644 index 00000000000..4ae3494a53c --- /dev/null +++ b/opentrons-ai-client/src/App.test.tsx @@ -0,0 +1,29 @@ +import React from 'react' +import { screen } from '@testing-library/react' +import { describe, it, vi, beforeEach } from 'vitest' + +import { renderWithProviders } from './__testing-utils__' +import { SidePanel } from './molecules/SidePanel' +import { ChatContainer } from './organisms/ChatContainer' + +import { App } from './App' + +vi.mock('./molecules/SidePanel') +vi.mock('./organisms/ChatContainer') + +const render = (): ReturnType => { + return renderWithProviders() +} + +describe('App', () => { + beforeEach(() => { + vi.mocked(SidePanel).mockReturnValue(
mock SidePanel
) + vi.mocked(ChatContainer).mockReturnValue(
mock ChatContainer
) + }) + + it('should render text', () => { + render() + screen.getByText('mock SidePanel') + screen.getByText('mock ChatContainer') + }) +}) diff --git a/opentrons-ai-client/src/App.tsx b/opentrons-ai-client/src/App.tsx new file mode 100644 index 00000000000..268a61b2e7f --- /dev/null +++ b/opentrons-ai-client/src/App.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import { DIRECTION_ROW, Flex } from '@opentrons/components' + +import { SidePanel } from './molecules/SidePanel' +import { ChatContainer } from './organisms/ChatContainer' + +export function App(): JSX.Element { + return ( + + + + + ) +} diff --git a/opentrons-ai-client/src/__testing-utils__/index.ts b/opentrons-ai-client/src/__testing-utils__/index.ts new file mode 100644 index 00000000000..e17c0ffbc31 --- /dev/null +++ b/opentrons-ai-client/src/__testing-utils__/index.ts @@ -0,0 +1,2 @@ +export * from './renderWithProviders' +export * from './matchers' diff --git a/opentrons-ai-client/src/__testing-utils__/matchers.ts b/opentrons-ai-client/src/__testing-utils__/matchers.ts new file mode 100644 index 00000000000..66234dbc915 --- /dev/null +++ b/opentrons-ai-client/src/__testing-utils__/matchers.ts @@ -0,0 +1,24 @@ +import type { Matcher } from '@testing-library/react' + +// Match things like

Some nested text

+// Use with either string match: getByText(nestedTextMatcher("Some nested text")) +// or regexp: getByText(nestedTextMatcher(/Some nested text/)) +export const nestedTextMatcher = (textMatch: string | RegExp): Matcher => ( + content, + node +) => { + const hasText = (n: typeof node): boolean => { + if (n == null || n.textContent === null) return false + return typeof textMatch === 'string' + ? Boolean(n?.textContent.match(textMatch)) + : textMatch.test(n.textContent) + } + const nodeHasText = hasText(node) + const childrenDontHaveText = + node != null && Array.from(node.children).every(child => !hasText(child)) + + return nodeHasText && childrenDontHaveText +} + +// need componentPropsMatcher +// need partialComponentPropsMatcher diff --git a/opentrons-ai-client/src/__testing-utils__/renderWithProviders.tsx b/opentrons-ai-client/src/__testing-utils__/renderWithProviders.tsx new file mode 100644 index 00000000000..e02ecb50de1 --- /dev/null +++ b/opentrons-ai-client/src/__testing-utils__/renderWithProviders.tsx @@ -0,0 +1,52 @@ +// render using targetted component using @testing-library/react +// with wrapping providers for i18next and redux +import * as React from 'react' +import { QueryClient, QueryClientProvider } from 'react-query' +import { I18nextProvider } from 'react-i18next' +import { Provider } from 'react-redux' +import { vi } from 'vitest' +import { render } from '@testing-library/react' +import { createStore } from 'redux' + +import type { PreloadedState, Store } from 'redux' +import type { RenderOptions, RenderResult } from '@testing-library/react' + +export interface RenderWithProvidersOptions extends RenderOptions { + initialState?: State + i18nInstance: React.ComponentProps['i18n'] +} + +export function renderWithProviders( + Component: React.ReactElement, + options?: RenderWithProvidersOptions +): [RenderResult, Store] { + const { initialState = {}, i18nInstance = null } = options ?? {} + + const store: Store = createStore( + vi.fn(), + initialState as PreloadedState + ) + store.dispatch = vi.fn() + store.getState = vi.fn(() => initialState) as () => State + + const queryClient = new QueryClient() + + const ProviderWrapper: React.ComponentType< + React.PropsWithChildren> + > = ({ children }) => { + const BaseWrapper = ( + + {children} + + ) + if (i18nInstance != null) { + return ( + {BaseWrapper} + ) + } else { + return BaseWrapper + } + } + + return [render(Component, { wrapper: ProviderWrapper }), store] +} diff --git a/opentrons-ai-client/src/assets/images/favicon/android-chrome-192x192.png b/opentrons-ai-client/src/assets/images/favicon/android-chrome-192x192.png new file mode 100644 index 00000000000..468479c76e7 Binary files /dev/null and b/opentrons-ai-client/src/assets/images/favicon/android-chrome-192x192.png differ diff --git a/opentrons-ai-client/src/assets/images/favicon/android-chrome-512x512.png b/opentrons-ai-client/src/assets/images/favicon/android-chrome-512x512.png new file mode 100644 index 00000000000..bab2df65fdb Binary files /dev/null and b/opentrons-ai-client/src/assets/images/favicon/android-chrome-512x512.png differ diff --git a/opentrons-ai-client/src/assets/images/favicon/apple-touch-icon.png b/opentrons-ai-client/src/assets/images/favicon/apple-touch-icon.png new file mode 100644 index 00000000000..ccbd74a497b Binary files /dev/null and b/opentrons-ai-client/src/assets/images/favicon/apple-touch-icon.png differ diff --git a/opentrons-ai-client/src/assets/images/favicon/favicon-16x16.png b/opentrons-ai-client/src/assets/images/favicon/favicon-16x16.png new file mode 100644 index 00000000000..4edd2e8b352 Binary files /dev/null and b/opentrons-ai-client/src/assets/images/favicon/favicon-16x16.png differ diff --git a/opentrons-ai-client/src/assets/images/favicon/favicon-32x32.png b/opentrons-ai-client/src/assets/images/favicon/favicon-32x32.png new file mode 100644 index 00000000000..eed71c70949 Binary files /dev/null and b/opentrons-ai-client/src/assets/images/favicon/favicon-32x32.png differ diff --git a/opentrons-ai-client/src/assets/images/favicon/favicon.ico b/opentrons-ai-client/src/assets/images/favicon/favicon.ico new file mode 100644 index 00000000000..d1266c550bf Binary files /dev/null and b/opentrons-ai-client/src/assets/images/favicon/favicon.ico differ diff --git a/opentrons-ai-client/src/assets/images/favicon/site.webmanifest b/opentrons-ai-client/src/assets/images/favicon/site.webmanifest new file mode 100644 index 00000000000..fe3af17b5d1 --- /dev/null +++ b/opentrons-ai-client/src/assets/images/favicon/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "opentrons_favicon", + "short_name": "favicon", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/opentrons-ai-client/src/assets/images/opentrons_logo.svg b/opentrons-ai-client/src/assets/images/opentrons_logo.svg new file mode 100644 index 00000000000..b183d161e81 --- /dev/null +++ b/opentrons-ai-client/src/assets/images/opentrons_logo.svg @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/opentrons-ai-client/src/assets/localization/en/index.ts b/opentrons-ai-client/src/assets/localization/en/index.ts new file mode 100644 index 00000000000..b5aa26621dd --- /dev/null +++ b/opentrons-ai-client/src/assets/localization/en/index.ts @@ -0,0 +1,7 @@ +import shared from './shared.json' +import protocol_generator from './protocol_generator.json' + +export const en = { + shared, + protocol_generator, +} diff --git a/opentrons-ai-client/src/assets/localization/en/protocol_generator.json b/opentrons-ai-client/src/assets/localization/en/protocol_generator.json new file mode 100644 index 00000000000..04509609800 --- /dev/null +++ b/opentrons-ai-client/src/assets/localization/en/protocol_generator.json @@ -0,0 +1,29 @@ +{ + "api": "API: An API level is 2.15", + "application": "Application: Your protocol's name, describing what it does.", + "commands": "Commands: List the protocol's steps, specifying quantities in microliters and giving exact source and destination locations.", + "disclaimer": "OpentronsAI can make mistakes. Review your protocol before running it on an Opentrons robot.", + "got_feedback": "Got feedback? We love to hear it.", + "make_sure_your_prompt": "Make sure your prompt includes the following:", + "metadata": "Metadata: Three pieces of information.", + "modules": "Modules: Thermocycler or Temperature Module.", + "opentronsai_asks": "OpentronsAI asks you to provide it!", + "opentronsai": "OpentronsAI", + "ot2_pipettes": "OT-2 pipettes: Include volume, number of channels, and generation.", + "pcr_flex": "PCR (Flex)", + "pcr": "PCR", + "reagent_transfer_flex": "Reagent Transfer (Flex)", + "reagent_transfer": "Reagent Transfer", + "robot": "Robot: OT-2.", + "share_your_thoughts": "Share your thoughts here", + "side_panel_body": "Write a prompt in natural language to generate a Reagent Transfer or a PCR protocol for the OT-2 or Opentrons Flex using the Opentrons Python Protocol API.", + "side_panel_header": "Use natural language to generate protocols with OpentronsAI powered by OpenAI", + "simulator_description": "Once OpentronsAI has written your protocol, type \"simulate\" in the prompt box to try it out.", + "tipracks_and_labware": "Tip racks and labware: Use names from the Opentrons Labware Library.", + "try_example_prompts": "Stuck? Try these example prompts to get started.", + "type_your_prompt": "Type your prompt...", + "well_allocations": "Well allocations: Describe where liquids should go in labware.", + "what_if_you": "What if you don’t provide all of those pieces of information? OpentronsAI asks you to provide it!", + "what_typeof_protocol": "What type of protocol do you need?", + "you": "You" +} diff --git a/opentrons-ai-client/src/assets/localization/en/shared.json b/opentrons-ai-client/src/assets/localization/en/shared.json new file mode 100644 index 00000000000..46cb365873f --- /dev/null +++ b/opentrons-ai-client/src/assets/localization/en/shared.json @@ -0,0 +1,3 @@ +{ + "send": "Send" +} diff --git a/opentrons-ai-client/src/assets/localization/index.ts b/opentrons-ai-client/src/assets/localization/index.ts new file mode 100644 index 00000000000..e92a7077ed9 --- /dev/null +++ b/opentrons-ai-client/src/assets/localization/index.ts @@ -0,0 +1,5 @@ +import { en } from './en' + +export const resources = { + en, +} diff --git a/opentrons-ai-client/src/assets/prompts/index.ts b/opentrons-ai-client/src/assets/prompts/index.ts new file mode 100644 index 00000000000..d581f250678 --- /dev/null +++ b/opentrons-ai-client/src/assets/prompts/index.ts @@ -0,0 +1 @@ +export * from './prompt-data' diff --git a/opentrons-ai-client/src/assets/prompts/prompt-data.ts b/opentrons-ai-client/src/assets/prompts/prompt-data.ts new file mode 100644 index 00000000000..b0276b47547 --- /dev/null +++ b/opentrons-ai-client/src/assets/prompts/prompt-data.ts @@ -0,0 +1,147 @@ +export const reagentTransfer = ` +Write a protocol for the Opentrons OT-2 as described below: + +Metadata: +- Application: Reagent transfer +- Robot: OT-2 +- API: 2.15 + +Pipette mount: +- P1000 Single-Channel GEN2 is mounted on left +- P300 Single-Channel GEN2 is mounted on right + +Labware: +- Source Labware: Thermo Scientific Nunc 96 Well Plate 2000 µL on slot 7 +- Destination Labware: Opentrons 24 Well Aluminum Block with NEST 0.5 mL Screwcap on slot 3 +- Tiprack: Opentrons 96 Filter Tip Rack 1000 µL on slot 4 + +Commands: +- Using P1000 Single-Channel GEN2 pipette on left mount, transfer 195.0 uL of reagent + from H10, F12, D7, B1, C8 wells in source labware + to first well in the destination labware. + Use new tip for each transfer. +` + +export const flexReagentTransfer = ` +Write a protocol for the Opentrons Flex as described below: + +Metadata and requirements: +- Application: Reagent transfer +- Robot: Flex +- API: 2.15 + +Pipette Mount: +- Flex 1-Channel 1000 µL Pipette is mounted on the left side +- Flex 1-Channel 50 µL Pipette is mounted on the right side + +Labware: +- Source Labware 1: NEST 1 Well Reservoir 195 mL is positioned on slot B1 +- Source Labware 2: Bio-Rad 384 Well Plate 50 µL is positioned on slot B2 +- Source Labware 3: Bio-Rad 96 Well Plate 200 µL is positioned on slot B3 +- Destination Labware 1: Corning 384 Well Plate 112 µL Flat is positioned on slot D1 +- Destination Labware 2: Corning 96 Well Plate 360 µL Flat is positioned on slot D2 +- Tiprack 1: Opentrons Flex 96 Filter Tip Rack 200 µL is used on slot A1 +- Tiprack 2: Opentrons Flex 96 Filter Tip Rack 50 µL is used on slot A2 + +Commands +- Using Flex 1-Channel 50 µL Pipette on right mount, transfer 15 µL from first of source labware 1 to each well + in destination labware 1 and destination labware 2. Reuse the same tip. +- Again using Flex 1-Channel 50 µL Pipette, transfer 20 µL from each well in source labware 2 to + each well in the destination labware 1. Reuse the same tip. +- Using Flex 1-Channel 1000 µL Pipette on left mount, transfer 100µL liquid from each well in source labware 3 + to each well in destination labware 2. Use a new tip each time. +` + +export const pcr = ` +Write a protocol for the Opentrons OT-2 as described below: + +Metadata: +- Application: ThermoPrime Taq DNA Polymerase, with 10x buffer and separate vial of 25 mM MgCl2Thermo Scientific kit PCR amplification +- Robot: OT-2 +- API: 2.15 + +Pipette mount: +- P20 Single Channel is mounted on the right side + +Modules: +- Thermocycler module is present on slot 7 +- Temperature module is place on slot 3 + +Labware: +- Source sample labware is Opentrons 96 Well Aluminum Block with NEST Well Plate 100 µL plate placed on slot 1 +- Source mastermix labware is Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap, placed on temperature module on slot 3 +- Destination Labware is an Opentrons Tough 96 Well Plate 200 µL PCR Full Skirt placed on thermocycler module on slot 7 +- 20 ul Filter tiprack is used on slot 4 + +Well allocation: +- source wells are first 41 wells column wise in both master mix and sample source plates +- destination wells: first 41 wells column wise on thermocycler + +Commands: +Note that every step is a single entity. Do not combine. Also, every step should be performed in order. +1. The total number of samples is 41 +2. Set the thermocycler such that: + - block temperature is 6 degree C + - lid temperature to 90 degree C + - lid open +3. Set the master mix temperature module at 10 C. The temperature module wait time is 50 seconds. +4. Transfer 10 uL of mastermix from source well to destination well. Use the same pipette tip for all transfers. +5. Transfer 3 ul of sample to destination well reusing tip everytime. After dispensing, mix the sample and mastermix +of 13 ul total volume 4 times and then perform blowout before dropping tip. +6. Close the lid of the thermocycler. +7. Set the thermocycle to following parameters (**note that each step is independent**): + Step 1: 66 degree C for 47 seconds for 1 cycles + Step 2: 88 degree C for 28 seconds, 82 degree C for 14 seconds, 68 degree C for 68 seconds for 15 cycles + Step 3: 70 degree C for 240 seconds for 1 cycles +Then, execute thermocycler profile for each step. +8. After the above three steps are completed, hold thermocycler block at 4 C +9. Open thermocycler lid +10. Deactivate the temperature modules +` + +export const flexPcr = ` +Write a protocol for the Opentrons Flex as described below: + +Metadata and requirements: +- Application: GeneAmp2x PCR amplification +- Robot: Flex +- API: 2.15 + +Pipette mount: +- Flex 1-Channel 50 µL Pipette is mounted on the right side + +Modules and adapters: +- Thermocycler GEN 2 module is present on slot A1+B1 +- Temperature module GEN 2 is place on slot D3 + +Labware: +- Source sample labware is Opentrons 96 Well Aluminum Block with NEST Well Plate 100 µL plate placed on slot D1 +- Source mastermix labware is Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap, placed on temperature module on slot D3 +- Destination Labware is an Opentrons Tough 96 Well Plate 200 µL PCR Full Skirt placed on thermocycler GEN 2 module +- Opentrons Flex 96 Filter Tip Rack 50 µL is used on slot C1 + +Sample position: +- source wells are first 64 wells column wise in both master mix and sample source plates +- destination wells: first 64 wells column wise on thermocycler + +Commands: +Note that every step is a single entity. Do not combine. Also, every step should be performed in order. +1. The total number of samples is 64 +2. Set the thermocycler such that + - block temperature is 6 degree C + - lid temperature to 90 degree C + - lid open +3. Set the master mix temperature module at 10 C. The temperature module wait time is 50 seconds. +4. Transfer 10 uL of mastermix from source well to destination well. Use the same pipette tip for all transfers. +5. Transfer 3 ul of sample to destination well reusing tip everytime. After dispensing, mix the sample and mastermix +of 13 ul total volume 4 times and then perform blowout before dropping tip. +6. Close the lid of the thermocycler. +7. Set the thermocycle to following parameters (**note that each step is independent**): + Step 1: 66 degree C for 47 seconds for 1 cycles + Step 2: 88 degree C for 28 seconds, 82 degree C for 14 seconds, 68 degree C for 68 seconds for 15 cycles + Step 3: 70 degree C for 240 seconds for 1 cycles +Then, execute thermocycler profile for each step. +8. After the above three steps are completed, hold thermocycler block at 4 C +9. Open thermocycler lid +10. Deactivate the temperature modules +` diff --git a/opentrons-ai-client/src/atoms/GlobalStyle/index.ts b/opentrons-ai-client/src/atoms/GlobalStyle/index.ts new file mode 100644 index 00000000000..782a2a0b91b --- /dev/null +++ b/opentrons-ai-client/src/atoms/GlobalStyle/index.ts @@ -0,0 +1,34 @@ +import { createGlobalStyle } from 'styled-components' +import { COLORS } from '@opentrons/components' +import '@fontsource/public-sans' +import '@fontsource/public-sans/600.css' +import '@fontsource/public-sans/700.css' + +export const GlobalStyle = createGlobalStyle` + * { + box-sizing: border-box; + margin: 0; + padding: 0; + font-family: 'Public Sans', 'sans-serif'; + } + + html, + body { + width: 100%; + height: 100%; + color: ${COLORS.black90}; + } + + a { + text-decoration: none; + } + + button { + border: none; + + &:focus, + &:active { + outline: 0; + } + } +` diff --git a/opentrons-ai-client/src/atoms/SendButton/__tests__/SendButton.test.tsx b/opentrons-ai-client/src/atoms/SendButton/__tests__/SendButton.test.tsx new file mode 100644 index 00000000000..dcf90ec1022 --- /dev/null +++ b/opentrons-ai-client/src/atoms/SendButton/__tests__/SendButton.test.tsx @@ -0,0 +1,53 @@ +import React from 'react' +import { describe, it, vi, beforeEach, expect } from 'vitest' +import { fireEvent, screen } from '@testing-library/react' +import { renderWithProviders } from '../../../__testing-utils__' + +import { SendButton } from '../index' + +const mockHandleClick = vi.fn() +const render = (props: React.ComponentProps) => { + return renderWithProviders() +} + +describe('SendButton', () => { + let props: React.ComponentProps + + beforeEach(() => { + props = { + handleClick: mockHandleClick, + disabled: true, + isLoading: false, + } + }) + it('should render button with send icon and its initially disabled', () => { + render(props) + const button = screen.getByRole('button') + expect(button).toBeDisabled() + screen.getByTestId('SendButton_icon_send') + }) + + it('should render button and its not disabled when disabled false', () => { + props = { ...props, disabled: false } + render(props) + const button = screen.getByRole('button') + expect(button).not.toBeDisabled() + screen.getByTestId('SendButton_icon_send') + }) + + it('should render button with spinner icon when isLoading', () => { + props = { ...props, isLoading: true } + render(props) + const button = screen.getByRole('button') + expect(button).toBeDisabled() + screen.getByTestId('SendButton_icon_ot-spinner') + }) + + it('should call a mock function when clicking the button', () => { + props = { ...props, disabled: false } + render(props) + const button = screen.getByRole('button') + fireEvent.click(button) + expect(mockHandleClick).toHaveBeenCalled() + }) +}) diff --git a/opentrons-ai-client/src/atoms/SendButton/index.tsx b/opentrons-ai-client/src/atoms/SendButton/index.tsx new file mode 100644 index 00000000000..e165762b2ab --- /dev/null +++ b/opentrons-ai-client/src/atoms/SendButton/index.tsx @@ -0,0 +1,74 @@ +import React from 'react' +import { css } from 'styled-components' + +import { + ALIGN_CENTER, + BORDERS, + Btn, + COLORS, + DISPLAY_FLEX, + Icon, + JUSTIFY_CENTER, +} from '@opentrons/components' + +interface SendButtonProps { + handleClick: () => void + disabled?: boolean + isLoading?: boolean +} + +export function SendButton({ + handleClick, + disabled = false, + isLoading = false, +}: SendButtonProps): JSX.Element { + const playButtonStyle = css` + -webkit-tap-highlight-color: transparent; + &:focus { + background-color: ${COLORS.blue60}; + color: ${COLORS.white}; + } + + &:hover { + background-color: ${COLORS.blue50}; + color: ${COLORS.white}; + } + + &:focus-visible { + background-color: ${COLORS.blue50}; + } + + &:active { + background-color: ${COLORS.blue60}; + color: ${COLORS.white}; + } + + &:disabled { + background-color: ${COLORS.grey35}; + color: ${COLORS.grey50}; + } + ` + return ( + + + + ) +} diff --git a/opentrons-ai-client/src/i18n.ts b/opentrons-ai-client/src/i18n.ts new file mode 100644 index 00000000000..0f7ef3bf6df --- /dev/null +++ b/opentrons-ai-client/src/i18n.ts @@ -0,0 +1,45 @@ +import i18n from 'i18next' +import capitalize from 'lodash/capitalize' +import startCase from 'lodash/startCase' +import { initReactI18next } from 'react-i18next' +import { resources } from './assets/localization' +import { titleCase } from '@opentrons/shared-data' + +i18n.use(initReactI18next).init( + { + resources, + lng: 'en', + fallbackLng: 'en', + debug: process.env.NODE_ENV === 'development', + ns: ['shared'], + defaultNS: 'shared', + interpolation: { + escapeValue: false, // not needed for react as it escapes by default + format: function (value, format, lng) { + if (format === 'upperCase') return value.toUpperCase() + if (format === 'lowerCase') return value.toLowerCase() + if (format === 'capitalize') return capitalize(value) + if (format === 'sentenceCase') return startCase(value) + if (format === 'titleCase') return titleCase(value) + return value + }, + }, + keySeparator: false, // use namespaces and context instead + saveMissing: true, + missingKeyHandler: (lng, ns, key) => { + process.env.NODE_ENV === 'test' + ? console.error(`Missing ${lng} Translation: key={${key}} ns={${ns}}`) + : console.warn(`Missing ${lng} Translation: key={${key}} ns={${ns}}`) + }, + }, + err => { + if (err) { + console.error( + 'Internationalization was not initialized properly. error: ', + err + ) + } + } +) + +export { i18n } diff --git a/opentrons-ai-client/src/main.tsx b/opentrons-ai-client/src/main.tsx new file mode 100644 index 00000000000..a2f1338bd7b --- /dev/null +++ b/opentrons-ai-client/src/main.tsx @@ -0,0 +1,21 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import { I18nextProvider } from 'react-i18next' +import { GlobalStyle } from './atoms/GlobalStyle' + +import { i18n } from './i18n' +import { App } from './App' + +const rootElement = document.getElementById('root') +if (rootElement != null) { + ReactDOM.createRoot(rootElement).render( + + + + + + + ) +} else { + console.error('Root element not found') +} diff --git a/opentrons-ai-client/src/molecules/ChatDisplay/ChatDisplay.stories.tsx b/opentrons-ai-client/src/molecules/ChatDisplay/ChatDisplay.stories.tsx new file mode 100644 index 00000000000..e3e0a1a6f36 --- /dev/null +++ b/opentrons-ai-client/src/molecules/ChatDisplay/ChatDisplay.stories.tsx @@ -0,0 +1,85 @@ +import React from 'react' +import { I18nextProvider } from 'react-i18next' +import { COLORS, Flex, SPACING } from '@opentrons/components' +import { i18n } from '../../i18n' +import { ChatDisplay } from './index' + +import type { Meta, StoryObj } from '@storybook/react' + +const meta: Meta = { + title: 'AI/molecules/ChatDisplay', + component: ChatDisplay, + decorators: [ + Story => ( + + + + + + ), + ], +} +export default meta +type Story = StoryObj + +export const OpentronsAI: Story = { + args: { + chat: { + role: 'assistant', + content: ` +## sample output from OpentronsAI + +\`\`\`py +from opentrons import protocol_api +# Metadata +metadata = { + 'protocolName': 'ThermoPrime Taq DNA Polymerase PCR Amplification', + 'author': 'Name ', + 'description': 'PCR amplification using ThermoPrime Taq DNA Polymerase kit', + 'apiLevel': '2.11' +} + +# Protocol run function +def run(protocol: protocol_api.ProtocolContext): + + # Constants + NO_OF_SAMPLES = 41 + SAMPLE_VOL = 3 # uL + MASTERMIX_VOL = 10 # uL + TC_SAMPLE_MASTERMIX_MIXES = 4 + TC_SAMPLE_MASTERMIX_MIX_VOLUME = SAMPLE_VOL + MASTERMIX_VOL + MASTERMIX_BLOCK_TEMP = 10 # degree C + TEMP_DECK_WAIT_TIME = 50 # seconds +\`\`\` +`, + }, + }, +} + +export const User: Story = { + args: { + chat: { + role: 'user', + content: ` + - Application: Reagent transfer + - Robot: OT-2 + - API: 2.13 + + Pipette mount: + - P1000 Single-Channel GEN2 is mounted on left + - P300 Single-Channel GEN2 is mounted on right + + Labware: + - Source Labware: Thermo Scientific Nunc 96 Well Plate 2000 µL on slot 7 + - Destination Labware: Opentrons 24 Well Aluminum Block with NEST 0.5 mL Screwcap on slot 3 + - Tiprack: Opentrons 96 Filter Tip Rack 1000 µL on slot 4 + + Commands: + - Using P1000 Single-Channel GEN2 pipette on left mount, transfer 195.0 uL of reagent + from H10, F12, D7, B1, C8 wells in source labware + to first well in the destination labware. + Use new tip for each transfer. + `, + }, + }, +} diff --git a/opentrons-ai-client/src/molecules/ChatDisplay/__tests__/ChatDisplay.test.tsx b/opentrons-ai-client/src/molecules/ChatDisplay/__tests__/ChatDisplay.test.tsx new file mode 100644 index 00000000000..98fd30274ee --- /dev/null +++ b/opentrons-ai-client/src/molecules/ChatDisplay/__tests__/ChatDisplay.test.tsx @@ -0,0 +1,46 @@ +import React from 'react' +import { screen } from '@testing-library/react' +import { describe, it, beforeEach } from 'vitest' +import { renderWithProviders } from '../../../__testing-utils__' +import { i18n } from '../../../i18n' + +import { ChatDisplay } from '../index' + +const render = (props: React.ComponentProps) => { + return renderWithProviders(, { i18nInstance: i18n }) +} + +describe('ChatDisplay', () => { + let props: React.ComponentProps + + beforeEach(() => { + props = { + chat: { + role: 'assistant', + content: 'mock text from the backend', + }, + } + }) + it('should display response from the backend and label', () => { + render(props) + screen.getByText('OpentronsAI') + screen.getByText('mock text from the backend') + // ToDO (kk:04/16/2024) activate the following when jsdom's issue is solved + // const display = screen.getByTextId('ChatDisplay_from_backend') + // expect(display).toHaveStyle(`background-color: ${COLORS.grey30}`) + }) + it('should display input from use and label', () => { + props = { + chat: { + role: 'user', + content: 'mock text from user input', + }, + } + render(props) + screen.getByText('You') + screen.getByText('mock text from user input') + // ToDO (kk:04/16/2024) activate the following when jsdom's issue is solved + // const display = screen.getByTextId('ChatDisplay_from_user') + // expect(display).toHaveStyle(`background-color: ${COLORS.blue}`) + }) +}) diff --git a/opentrons-ai-client/src/molecules/ChatDisplay/index.tsx b/opentrons-ai-client/src/molecules/ChatDisplay/index.tsx new file mode 100644 index 00000000000..3b5c54ebbc6 --- /dev/null +++ b/opentrons-ai-client/src/molecules/ChatDisplay/index.tsx @@ -0,0 +1,92 @@ +import React from 'react' +// import { css } from 'styled-components' +import { useTranslation } from 'react-i18next' +import Markdown from 'react-markdown' +import { + BORDERS, + COLORS, + DIRECTION_COLUMN, + Flex, + SPACING, + StyledText, +} from '@opentrons/components' + +import type { ChatData } from '../../resources/types' + +interface ChatDisplayProps { + chat: ChatData +} + +export function ChatDisplay({ chat }: ChatDisplayProps): JSX.Element { + const { t } = useTranslation('protocol_generator') + const { role, content } = chat + const isUser = role === 'user' + return ( + + {isUser ? t('you') : t('opentronsai')} + {/* text should be markdown so this component will have a package or function to parse markdown */} + + {/* ToDo (kk:05/02/2024) This part is waiting for Mel's design */} + {/* + {content} + */} + {content} + + + ) +} + +// ToDo (kk:05/02/2024) This part is waiting for Mel's design +// function ExternalLink(props: JSX.IntrinsicAttributes): JSX.Element { +// return +// } + +// function ParagraphText(props: JSX.IntrinsicAttributes): JSX.Element { +// return +// } + +// function HeaderText(props: JSX.IntrinsicAttributes): JSX.Element { +// return +// } + +// function ListItemText(props: JSX.IntrinsicAttributes): JSX.Element { +// return +// } + +// function UnnumberedListText(props: JSX.IntrinsicAttributes): JSX.Element { +// return +// } + +// const CODE_TEXT_STYLE = css` +// padding: ${SPACING.spacing16}; +// font-family: monospace; +// color: ${COLORS.white}; +// background-color: ${COLORS.black90}; +// ` + +// function CodeText(props: JSX.IntrinsicAttributes): JSX.Element { +// return +// } diff --git a/opentrons-ai-client/src/molecules/InputPrompt/__tests__/InputPrompt.test.tsx b/opentrons-ai-client/src/molecules/InputPrompt/__tests__/InputPrompt.test.tsx new file mode 100644 index 00000000000..f46d0722119 --- /dev/null +++ b/opentrons-ai-client/src/molecules/InputPrompt/__tests__/InputPrompt.test.tsx @@ -0,0 +1,29 @@ +import React from 'react' +import { describe, it, expect } from 'vitest' +import { fireEvent, screen } from '@testing-library/react' +import { renderWithProviders } from '../../../__testing-utils__' +import { i18n } from '../../../i18n' +import { InputPrompt } from '../index' + +const render = () => { + return renderWithProviders(, { i18nInstance: i18n }) +} + +describe('InputPrompt', () => { + it('should render textarea and disabled button', () => { + render() + screen.getByRole('textbox') + screen.queryByPlaceholderText('Type your prompt...') + screen.getByRole('button') + expect(screen.getByRole('button')).toBeDisabled() + }) + + it('should make send button not disabled when a user inputs something in textarea', () => { + render() + const textbox = screen.getByRole('textbox') + fireEvent.change(textbox, { target: { value: ['test'] } }) + expect(screen.getByRole('button')).not.toBeDisabled() + }) + + // ToDo (kk:04/19/2024) add more test cases +}) diff --git a/opentrons-ai-client/src/molecules/InputPrompt/index.tsx b/opentrons-ai-client/src/molecules/InputPrompt/index.tsx new file mode 100644 index 00000000000..e8a8dda0c20 --- /dev/null +++ b/opentrons-ai-client/src/molecules/InputPrompt/index.tsx @@ -0,0 +1,158 @@ +import React from 'react' +import { useTranslation } from 'react-i18next' +import styled, { css } from 'styled-components' +import { useForm } from 'react-hook-form' +import { useAtom } from 'jotai' +import axios from 'axios' + +import { + ALIGN_CENTER, + BORDERS, + COLORS, + DIRECTION_ROW, + Flex, + JUSTIFY_CENTER, + SPACING, + TYPOGRAPHY, +} from '@opentrons/components' +import { SendButton } from '../../atoms/SendButton' +import { preparedPromptAtom, chatDataAtom } from '../../resources/atoms' + +import type { ChatData } from '../../resources/types' + +// ToDo (kk:05/02/2024) This url is temporary +const url = 'http://localhost:8000/streaming/ask' + +interface InputType { + userPrompt: string +} + +export function InputPrompt(): JSX.Element { + const { t } = useTranslation('protocol_generator') + const { register, watch, setValue, reset } = useForm({ + defaultValues: { + userPrompt: '', + }, + }) + const [preparedPrompt] = useAtom(preparedPromptAtom) + const [, setChatData] = useAtom(chatDataAtom) + const [submitted, setSubmitted] = React.useState(false) + + const [data, setData] = React.useState(null) + const [loading, setLoading] = React.useState(false) + const [error, setError] = React.useState('') + + const userPrompt = watch('userPrompt') ?? '' + + const calcTextAreaHeight = (): number => { + const rowsNum = userPrompt.split('\n').length + return rowsNum + } + + const fetchData = async (prompt: string): Promise => { + if (prompt !== '') { + setLoading(true) + try { + const response = await axios.post(url, { + headers: { + 'Content-Type': 'application/json', + }, + query: prompt, + }) + setData(response.data) + } catch (err) { + setError('Error fetching data from the API.') + } finally { + setLoading(false) + } + } + } + + const handleClick = (): void => { + const userInput: ChatData = { + role: 'user', + content: userPrompt, + } + setChatData(chatData => [...chatData, userInput]) + void fetchData(userPrompt) + setSubmitted(true) + reset() + } + + React.useEffect(() => { + if (preparedPrompt !== '') setValue('userPrompt', preparedPrompt as string) + }, [preparedPrompt, setValue]) + + React.useEffect(() => { + if (submitted && data && !loading) { + const { role, content } = data.data + const assistantResponse: ChatData = { + role, + content, + } + setChatData(chatData => [...chatData, assistantResponse]) + setSubmitted(false) + } + }, [data, loading, submitted]) + + // ToDo (kk:05/02/2024) This is also temp. Asking the design about error. + console.error('error', error) + + return ( + + + + + + + ) +} + +const StyledForm = styled.form` + width: 100%; +` + +const CONTAINER_STYLE = css` + padding: ${SPACING.spacing40}; + grid-gap: ${SPACING.spacing40}; + flex-direction: ${DIRECTION_ROW}; + background-color: ${COLORS.white}; + border-radius: ${BORDERS.borderRadius4}; + justify-content: ${JUSTIFY_CENTER}; + align-items: ${ALIGN_CENTER}; + max-height: 21.25rem; + + &:focus-within { + border: 1px ${BORDERS.styleSolid}${COLORS.blue50}; + } +` + +const StyledTextarea = styled.textarea` + resize: none; + min-height: 3.75rem; + max-height: 17.25rem; + overflow-y: auto; + background-color: ${COLORS.white}; + border: none; + outline: none; + padding: 0; + box-shadow: none; + color: ${COLORS.black90}; + width: 100%; + font-size: ${TYPOGRAPHY.fontSize20}; + line-height: ${TYPOGRAPHY.lineHeight24}; + + ::placeholder { + position: absolute; + top: 50%; + transform: translateY(-50%); + } +` diff --git a/opentrons-ai-client/src/molecules/PromptGuide/PromptGuide.stories.tsx b/opentrons-ai-client/src/molecules/PromptGuide/PromptGuide.stories.tsx new file mode 100644 index 00000000000..1a29b80c709 --- /dev/null +++ b/opentrons-ai-client/src/molecules/PromptGuide/PromptGuide.stories.tsx @@ -0,0 +1,21 @@ +import React from 'react' +import { I18nextProvider } from 'react-i18next' +import { i18n } from '../../i18n' +import { PromptGuide as PromptGuideComponent } from './index' + +import type { Meta, StoryObj } from '@storybook/react' + +const meta: Meta = { + title: 'AI/molecules/PromptGuide', + component: PromptGuideComponent, + decorators: [ + Story => ( + + + + ), + ], +} +export default meta +type Story = StoryObj +export const PromptGuide: Story = {} diff --git a/opentrons-ai-client/src/molecules/PromptGuide/__tests__/PromptGuide.test.tsx b/opentrons-ai-client/src/molecules/PromptGuide/__tests__/PromptGuide.test.tsx new file mode 100644 index 00000000000..48ecca239f8 --- /dev/null +++ b/opentrons-ai-client/src/molecules/PromptGuide/__tests__/PromptGuide.test.tsx @@ -0,0 +1,49 @@ +import React from 'react' +import { describe, it, expect } from 'vitest' +import { screen } from '@testing-library/react' +import { renderWithProviders } from '../../../__testing-utils__' +import { i18n } from '../../../i18n' + +import { PromptGuide } from '../index' + +const LABWARE_LIBRARY_URL = 'https://labware.opentrons.com/' + +const render = () => { + return renderWithProviders(, { i18nInstance: i18n }) +} + +describe('PromptGuide', () => { + it('should render text', () => { + render() + screen.getByText('What type of protocol do you need?') + screen.getByText('Make sure your prompt includes the following:') + screen.getByText('Metadata: Three pieces of information.') + screen.getByText( + "Application: Your protocol's name, describing what it does." + ) + screen.getByText('Robot: OT-2.') + screen.getByText('API: An API level is 2.15') + screen.getByText( + 'OT-2 pipettes: Include volume, number of channels, and generation.' + ) + screen.getByText('Modules: Thermocycler or Temperature Module.') + screen.getByText( + 'Well allocations: Describe where liquids should go in labware.' + ) + screen.getByText( + "Commands: List the protocol's steps, specifying quantities in microliters and giving exact source and destination locations." + ) + screen.getByText( + 'What if you don’t provide all of those pieces of information?' + ) + screen.getByText('OpentronsAI asks you to provide it!') + screen.getByText( + 'Once OpentronsAI has written your protocol, type "simulate" in the prompt box to try it out.' + ) + }) + it('should have the right url', () => { + render() + const link = screen.getByRole('link', { name: 'Opentrons Labware Library' }) + expect(link).toHaveAttribute('href', LABWARE_LIBRARY_URL) + }) +}) diff --git a/opentrons-ai-client/src/molecules/PromptGuide/index.tsx b/opentrons-ai-client/src/molecules/PromptGuide/index.tsx new file mode 100644 index 00000000000..a0d6925c9bf --- /dev/null +++ b/opentrons-ai-client/src/molecules/PromptGuide/index.tsx @@ -0,0 +1,115 @@ +import React from 'react' +import { Trans, useTranslation } from 'react-i18next' +import styled, { css } from 'styled-components' +import { + BORDERS, + COLORS, + DIRECTION_COLUMN, + Flex, + Link, + SPACING, + StyledText, + TYPOGRAPHY, +} from '@opentrons/components' + +const LABWARE_LIBRARY_URL = 'https://labware.opentrons.com/' + +export function PromptGuide(): JSX.Element { + const { t } = useTranslation('protocol_generator') + + return ( + + + {t('what_typeof_protocol')} + + + + + {t('make_sure_your_prompt')} + + +
    +
  • + {t('metadata')} + +
  • + {t('application')} +
  • +
  • + {t('robot')} +
  • +
  • + {t('api')} +
  • + + +
  • + {t('ot2_pipettes')} +
  • +
  • + {t('modules')} +
  • +
  • + {t('well_allocations')} +
  • +
  • + , + span: , + }} + /> +
  • +
  • + {t('commands')} +
  • +
+
+
+ , + span: , + }} + /> + + {t('simulator_description')} + +
+ ) +} + +const HEADER_TEXT_STYLE = css` + font-size: ${TYPOGRAPHY.fontSize28}; + line-height: ${TYPOGRAPHY.lineHeight36}; + font-weight: ${TYPOGRAPHY.fontWeightSemiBold}; +` +const BODY_TEXT_STYLE = css` + font-size: ${TYPOGRAPHY.fontSize20}; + line-height: ${TYPOGRAPHY.lineHeight24}; +` +const StyledUl = styled.ul` + padding-left: ${SPACING.spacing16}; + list-style-type: disc; +` + +const ExternalLink = styled(Link)` + font-size: ${TYPOGRAPHY.fontSize20}; + line-height: ${TYPOGRAPHY.lineHeight24}; + color: ${COLORS.black90}; + text-decoration: ${TYPOGRAPHY.textDecorationUnderline}; +` diff --git a/opentrons-ai-client/src/molecules/SidePanel/SidePanel.stories.tsx b/opentrons-ai-client/src/molecules/SidePanel/SidePanel.stories.tsx new file mode 100644 index 00000000000..1c1d30b7548 --- /dev/null +++ b/opentrons-ai-client/src/molecules/SidePanel/SidePanel.stories.tsx @@ -0,0 +1,21 @@ +import React from 'react' +import { I18nextProvider } from 'react-i18next' +import { i18n } from '../../i18n' +import { SidePanel as SidePanelComponent } from './index' + +import type { Meta, StoryObj } from '@storybook/react' + +const meta: Meta = { + title: 'AI/molecules/SidePanel', + component: SidePanelComponent, + decorators: [ + Story => ( + + + + ), + ], +} +export default meta +type Story = StoryObj +export const SidePanel: Story = {} diff --git a/opentrons-ai-client/src/molecules/SidePanel/__tests__/SidePanel.test.tsx b/opentrons-ai-client/src/molecules/SidePanel/__tests__/SidePanel.test.tsx new file mode 100644 index 00000000000..56cb50f73fc --- /dev/null +++ b/opentrons-ai-client/src/molecules/SidePanel/__tests__/SidePanel.test.tsx @@ -0,0 +1,48 @@ +import React from 'react' +import { screen } from '@testing-library/react' +import { describe, it, expect } from 'vitest' + +import { renderWithProviders } from '../../../__testing-utils__' +import { i18n } from '../../../i18n' + +import { SidePanel } from '../index' + +const LOGO_FILE_NAME = + '/opentrons-ai-client/src/assets/images/opentrons_logo.svg' + +const FEEDBACK_FORM_LINK = 'https://opentrons-ai-beta.paperform.co/' + +const render = (): ReturnType => { + return renderWithProviders(, { + i18nInstance: i18n, + }) +} + +describe('SidePanel', () => { + it('should render logo and text', () => { + render() + const image = screen.getByRole('img') + expect(image.getAttribute('src')).toEqual(LOGO_FILE_NAME) + screen.getByText( + 'Use natural language to generate protocols with OpentronsAI powered by OpenAI' + ) + screen.getByText( + 'Write a prompt in natural language to generate a Reagent Transfer or a PCR protocol for the OT-2 or Opentrons Flex using the Opentrons Python Protocol API.' + ) + screen.getByText('Stuck? Try these example prompts to get started.') + screen.getByText('Got feedback? We love to hear it.') + const link = screen.getByRole('link', { + name: 'Share your thoughts here', + }) + expect(link).toHaveAttribute('href', FEEDBACK_FORM_LINK) + }) + + it('should render buttons', () => { + render() + screen.getByRole('button', { name: 'PCR' }) + screen.getByRole('button', { name: 'PCR (Flex)' }) + screen.getByRole('button', { name: 'Reagent Transfer' }) + screen.getByRole('button', { name: 'Reagent Transfer (Flex)' }) + }) + it.todo('should call a mock function when clicking a button') +}) diff --git a/opentrons-ai-client/src/molecules/SidePanel/index.tsx b/opentrons-ai-client/src/molecules/SidePanel/index.tsx new file mode 100644 index 00000000000..59a998e543c --- /dev/null +++ b/opentrons-ai-client/src/molecules/SidePanel/index.tsx @@ -0,0 +1,96 @@ +import React from 'react' +import styled, { css } from 'styled-components' +import { useTranslation } from 'react-i18next' +import { + COLORS, + DIRECTION_COLUMN, + Flex, + Link, + SPACING, + StyledText, + TYPOGRAPHY, + WRAP, +} from '@opentrons/components' +import { PromptButton } from '../../organisms/PromptButton' +import LOGO_PATH from '../../assets/images/opentrons_logo.svg' + +const IMAGE_ALT = 'Opentrons logo' +const FEEDBACK_FORM_LINK = 'https://opentrons-ai-beta.paperform.co/' +export function SidePanel(): JSX.Element { + const { t } = useTranslation('protocol_generator') + return ( + + {/* logo */} + + {IMAGE_ALT} + + + {/* body text */} + + + {t('side_panel_header')} + + {t('side_panel_body')} + + + {/* buttons */} + + + {t('try_example_prompts')} + + + + + + + + + + + + {t('got_feedback')} + + + {t('share_your_thoughts')} + + + + ) +} + +const HEADER_TEXT_STYLE = css` + font-size: ${TYPOGRAPHY.fontSize32}; + line-height: ${TYPOGRAPHY.lineHeight42}; + font-weight: ${TYPOGRAPHY.fontWeightBold}; + color: ${COLORS.white}; +` +const BODY_TEXT_STYLE = css` + font-size: ${TYPOGRAPHY.fontSize20}; + line-height: ${TYPOGRAPHY.lineHeight24}; + font-weight: ${TYPOGRAPHY.fontWeightRegular}; + color: ${COLORS.white}; +` +const BUTTON_GUIDE_TEXT_STYLE = css` + font-size: ${TYPOGRAPHY.fontSize20}; + line-height: ${TYPOGRAPHY.lineHeight24}; + font-weight: ${TYPOGRAPHY.fontWeightSemiBold}; + color: ${COLORS.white}; +` + +const FeedbackLink = styled(Link)` + font-size: ${TYPOGRAPHY.fontSize20}; + line-height: ${TYPOGRAPHY.lineHeight24}; + font-weight: ${TYPOGRAPHY.fontWeightBold}; + color: ${COLORS.white}; + text-decoration: ${TYPOGRAPHY.textDecorationUnderline}; +` diff --git a/opentrons-ai-client/src/organisms/ChatContainer/ChatContainer.stories.tsx b/opentrons-ai-client/src/organisms/ChatContainer/ChatContainer.stories.tsx new file mode 100644 index 00000000000..de3ba584302 --- /dev/null +++ b/opentrons-ai-client/src/organisms/ChatContainer/ChatContainer.stories.tsx @@ -0,0 +1,21 @@ +import React from 'react' +import { I18nextProvider } from 'react-i18next' +import { i18n } from '../../i18n' +import { ChatContainer as ChatContainerComponent } from './index' + +import type { Meta, StoryObj } from '@storybook/react' + +const meta: Meta = { + title: 'AI/organisms/ChatContainer', + component: ChatContainerComponent, + decorators: [ + Story => ( + + + + ), + ], +} +export default meta +type Story = StoryObj +export const ChatContainer: Story = {} diff --git a/opentrons-ai-client/src/organisms/ChatContainer/__tests__/ChatContainer.test.tsx b/opentrons-ai-client/src/organisms/ChatContainer/__tests__/ChatContainer.test.tsx new file mode 100644 index 00000000000..406e7889878 --- /dev/null +++ b/opentrons-ai-client/src/organisms/ChatContainer/__tests__/ChatContainer.test.tsx @@ -0,0 +1,35 @@ +import React from 'react' +import { screen } from '@testing-library/react' +import { describe, it, vi, beforeEach } from 'vitest' +import { renderWithProviders } from '../../../__testing-utils__' +import { i18n } from '../../../i18n' +import { PromptGuide } from '../../../molecules/PromptGuide' +import { InputPrompt } from '../../../molecules/InputPrompt' +import { ChatContainer } from '../index' + +vi.mock('../../../molecules/PromptGuide') +vi.mock('../../../molecules/InputPrompt') + +const render = (): ReturnType => { + return renderWithProviders(, { + i18nInstance: i18n, + }) +} + +describe('ChatContainer', () => { + beforeEach(() => { + vi.mocked(PromptGuide).mockReturnValue(
mock PromptGuide
) + vi.mocked(InputPrompt).mockReturnValue(
mock InputPrompt
) + }) + it('should render prompt guide and text', () => { + render() + screen.getByText('OpentronsAI') + screen.getByText('mock PromptGuide') + screen.getByText('mock InputPrompt') + screen.getByText( + 'OpentronsAI can make mistakes. Review your protocol before running it on an Opentrons robot.' + ) + }) + + // ToDo (kk:04/16/2024) Add more test cases +}) diff --git a/opentrons-ai-client/src/organisms/ChatContainer/index.tsx b/opentrons-ai-client/src/organisms/ChatContainer/index.tsx new file mode 100644 index 00000000000..8a120c65112 --- /dev/null +++ b/opentrons-ai-client/src/organisms/ChatContainer/index.tsx @@ -0,0 +1,79 @@ +import React from 'react' +import { useTranslation } from 'react-i18next' +import styled, { css } from 'styled-components' +import { useAtom } from 'jotai' + +import { + COLORS, + DIRECTION_COLUMN, + Flex, + POSITION_ABSOLUTE, + POSITION_RELATIVE, + SPACING, + StyledText, + TYPOGRAPHY, +} from '@opentrons/components' +import { PromptGuide } from '../../molecules/PromptGuide' +import { InputPrompt } from '../../molecules/InputPrompt' +import { ChatDisplay } from '../../molecules/ChatDisplay' +import { chatDataAtom } from '../../resources/atoms' + +export function ChatContainer(): JSX.Element { + const { t } = useTranslation('protocol_generator') + const [chatData] = useAtom(chatDataAtom) + + return ( + + {/* This will be updated when input textbox and function are implemented */} + + + + {t('opentronsai')} + {/* Prompt Guide remain as a reference for users. */} + + {chatData.length > 0 + ? chatData.map((chat, index) => ( + + )) + : null} + + + + {t('disclaimer')} + + + + ) +} + +const ChatDataContainer = styled(Flex)` + max-height: calc(100vh); + overflow-y: auto; + flex-direction: ${DIRECTION_COLUMN}; + grid-gap: ${SPACING.spacing12}; + width: 100%; +` + +const DISCLAIMER_TEXT_STYLE = css` + color: ${COLORS.grey55}; + font-size: ${TYPOGRAPHY.fontSize20}; + line-height: ${TYPOGRAPHY.lineHeight24}; + text-align: ${TYPOGRAPHY.textAlignCenter}; +` diff --git a/opentrons-ai-client/src/organisms/PromptButton/PromptButton.stories.tsx b/opentrons-ai-client/src/organisms/PromptButton/PromptButton.stories.tsx new file mode 100644 index 00000000000..f300b302393 --- /dev/null +++ b/opentrons-ai-client/src/organisms/PromptButton/PromptButton.stories.tsx @@ -0,0 +1,43 @@ +import React from 'react' +import { PromptButton as PromptButtonComponent } from '.' + +import type { Meta, StoryObj } from '@storybook/react' + +const buttonTextOptions = [ + 'Reagent Transfer', + 'Reagent Transfer (Flex)', + 'PCR', + 'PCR (Flex)', +] + +// ToDo (kk:04/22/2024) fix this stories +const meta: Meta = { + title: 'AI/organisms/PromptButton', + component: PromptButtonComponent, + argTypes: { + buttonText: { + control: { + type: 'select', + }, + options: buttonTextOptions, + }, + }, + decorators: [ + Story => { + return ( + <> + + + ) + }, + ], +} +export default meta + +type Story = StoryObj + +export const PromptButton: Story = { + args: { + buttonText: 'Reagent Transfer', + }, +} diff --git a/opentrons-ai-client/src/organisms/PromptButton/__tests__/PromptButton.test.tsx b/opentrons-ai-client/src/organisms/PromptButton/__tests__/PromptButton.test.tsx new file mode 100644 index 00000000000..d4659cc3c84 --- /dev/null +++ b/opentrons-ai-client/src/organisms/PromptButton/__tests__/PromptButton.test.tsx @@ -0,0 +1,36 @@ +import React from 'react' +import { useAtom } from 'jotai' +import { fireEvent, screen, renderHook } from '@testing-library/react' +import { describe, it, beforeEach, expect } from 'vitest' + +import { renderWithProviders } from '../../../__testing-utils__' +import { reagentTransfer } from '../../../assets/prompts' +import { preparedPromptAtom } from '../../../resources/atoms' +import { PromptButton } from '../index' + +const render = (props: React.ComponentProps) => { + return renderWithProviders() +} + +describe('PromptButton', () => { + let props: React.ComponentProps + beforeEach(() => { + props = { + buttonText: 'Reagent Transfer', + } + }) + + it('should render text', () => { + render(props) + screen.getByRole('button', { name: 'Reagent Transfer' }) + }) + + it('should call a mock function when clicking a button', () => { + render(props) + const button = screen.getByRole('button', { name: 'Reagent Transfer' }) + fireEvent.click(button) + const { result } = renderHook(() => useAtom(preparedPromptAtom)) + fireEvent.click(button) + expect(result.current[0]).toBe(reagentTransfer) + }) +}) diff --git a/opentrons-ai-client/src/organisms/PromptButton/index.tsx b/opentrons-ai-client/src/organisms/PromptButton/index.tsx new file mode 100644 index 00000000000..13a12cb492c --- /dev/null +++ b/opentrons-ai-client/src/organisms/PromptButton/index.tsx @@ -0,0 +1,46 @@ +import React from 'react' +import styled from 'styled-components' +import { useAtom } from 'jotai' +import { BORDERS, PrimaryButton } from '@opentrons/components' +import { + reagentTransfer, + flexReagentTransfer, + pcr, + flexPcr, +} from '../../assets/prompts' +import { preparedPromptAtom } from '../../resources/atoms' + +interface PromptButtonProps { + buttonText: string +} + +// ToDo (kk:04/22/2024) This record would be needed to be more generic +const PROMPT_BY_NAME: Record = { + 'Reagent Transfer': { + prompt: reagentTransfer, + }, + 'Reagent Transfer (Flex)': { + prompt: flexReagentTransfer, + }, + PCR: { + prompt: pcr, + }, + 'PCR (Flex)': { + prompt: flexPcr, + }, +} + +export function PromptButton({ buttonText }: PromptButtonProps): JSX.Element { + const [, setPreparedPrompt] = useAtom(preparedPromptAtom) + const handleClick = (): void => { + const { prompt } = PROMPT_BY_NAME[buttonText] + setPreparedPrompt(prompt) + } + + return {buttonText} +} + +const PromptBtn = styled(PrimaryButton)` + border-radius: ${BORDERS.borderRadiusFull}; + white-space: nowrap; +` diff --git a/opentrons-ai-client/src/resources/atoms.ts b/opentrons-ai-client/src/resources/atoms.ts new file mode 100644 index 00000000000..98ebd7df6f1 --- /dev/null +++ b/opentrons-ai-client/src/resources/atoms.ts @@ -0,0 +1,9 @@ +// jotai's atoms +import { atom } from 'jotai' +import type { ChatData } from './types' + +/** preparedPromptAtom is for PromptButton */ +export const preparedPromptAtom = atom('') + +/** ChatDataAtom is for chat data (user prompt and response from OpenAI API) */ +export const chatDataAtom = atom([]) diff --git a/opentrons-ai-client/src/resources/types.ts b/opentrons-ai-client/src/resources/types.ts new file mode 100644 index 00000000000..a0f5ebca959 --- /dev/null +++ b/opentrons-ai-client/src/resources/types.ts @@ -0,0 +1,6 @@ +export interface ChatData { + /** assistant: ChatGPT API, user: user */ + role: 'assistant' | 'user' + /** content ChatGPT API return or user prompt */ + content: string +} diff --git a/opentrons-ai-client/tsconfig-data.json b/opentrons-ai-client/tsconfig-data.json new file mode 100644 index 00000000000..79a9673faa9 --- /dev/null +++ b/opentrons-ai-client/tsconfig-data.json @@ -0,0 +1,12 @@ +{ + "extends": "../tsconfig-base.json", + "references": [], + "compilerOptions": { + "composite": true, + "emitDeclarationOnly": false, + "rootDir": ".", + "outDir": "lib" + }, + "include": ["src/**/*.json", "fixtures/**/*.json", "vite.config.ts"], + "exclude": ["**/*.ts", "**/*.tsx"] +} diff --git a/opentrons-ai-client/tsconfig.json b/opentrons-ai-client/tsconfig.json new file mode 100644 index 00000000000..b3c6dc275a8 --- /dev/null +++ b/opentrons-ai-client/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../tsconfig-base.json", + "references": [ + { + "path": "./tsconfig-data.json" + }, + { + "path": "../components" + } + ], + "compilerOptions": { + "rootDir": "src", + "outDir": "lib" + }, + "include": ["typings", "src"] +} diff --git a/opentrons-ai-client/typings/images.d.ts b/opentrons-ai-client/typings/images.d.ts new file mode 100644 index 00000000000..9dcd2f68792 --- /dev/null +++ b/opentrons-ai-client/typings/images.d.ts @@ -0,0 +1,15 @@ +declare module '*.png' { + const image: string + // eslint-disable-next-line import/no-default-export + export default image +} +declare module '*.svg' { + const image: string + // eslint-disable-next-line import/no-default-export + export default image +} +declare module '*.webm' { + const image: string + // eslint-disable-next-line import/no-default-export + export default image +} diff --git a/opentrons-ai-client/typings/styled-components.d.ts b/opentrons-ai-client/typings/styled-components.d.ts new file mode 100644 index 00000000000..5d6296f94be --- /dev/null +++ b/opentrons-ai-client/typings/styled-components.d.ts @@ -0,0 +1 @@ +import 'styled-components/cssprop' diff --git a/opentrons-ai-client/vite.config.ts b/opentrons-ai-client/vite.config.ts new file mode 100644 index 00000000000..ee557f68d62 --- /dev/null +++ b/opentrons-ai-client/vite.config.ts @@ -0,0 +1,43 @@ +import path from 'path' +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + // this makes imports relative rather than absolute + base: '', + build: { + // Relative to the root + outDir: 'dist', + }, + plugins: [ + react({ + include: '**/*.tsx', + babel: { + // Use babel.config.js files + configFile: true, + }, + }), + ], + optimizeDeps: { + esbuildOptions: { + target: 'es2020', + }, + }, + css: { + postcss: { + plugins: [], + }, + }, + define: { + 'process.env': process.env, + global: 'globalThis', + }, + resolve: { + alias: { + '@opentrons/components/styles': path.resolve( + '../components/src/index.module.css' + ), + '@opentrons/components': path.resolve('../components/src/index.ts'), + }, + }, +}) diff --git a/opentrons-ai-server/Makefile b/opentrons-ai-server/Makefile new file mode 100644 index 00000000000..9de2141f6a0 --- /dev/null +++ b/opentrons-ai-server/Makefile @@ -0,0 +1,2 @@ +# opentrons ai server makefile +# TBD \ No newline at end of file diff --git a/opentrons-ai-server/README.md b/opentrons-ai-server/README.md new file mode 100644 index 00000000000..e00cdc1af3d --- /dev/null +++ b/opentrons-ai-server/README.md @@ -0,0 +1,39 @@ +# Opentrons AI Backend + +## Overview + +The Opentrons AI application's server. + +## Developing + +To get started: clone the `Opentrons/opentrons` repository, set up your computer for development as specified in the [contributing guide][contributing-guide-setup], and then: + +```shell +# change into the cloned directory +cd opentrons +# prerequisite: install dependencies as specified in project setup +make setup +# launch the dev server +make -C opentrons-ai-server dev +``` + +## Stack and structure + +The UI stack is built using: + +- [OpenAI Python API library][] + +Some important directories: + +- `opentrons-ai-client` — Opentrons AI application's client-side + +## Testing + +TBD + +## Building + +TBD + +[pytest]: https://docs.pytest.org/en/ +[openai python api library]: https://pypi.org/project/openai/ diff --git a/package.json b/package.json index a38a11bdcd3..5b16dff3979 100755 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "@storybook/addon-links": "^7.6.16", "@storybook/react": "^7.6.16", "@storybook/react-vite": "^7.6.16", - "@testing-library/jest-dom": "6.4.0", + "@testing-library/jest-dom": "6.4.2", "@testing-library/react": "14.2.1", "@testing-library/user-event": "13.5.0", "@types/express": "^4.17.11", @@ -73,7 +73,7 @@ "conventional-changelog": "^3.1.25", "core-js": "^3.6.4", "css-loader": "^3.2.0", - "cypress": "^6.6.0", + "cypress": "13.7.1", "cypress-file-upload": "3.5.3", "cz-conventional-changelog": "2.1.0", "decompress": "4.2.1", @@ -105,6 +105,7 @@ "handlebars-loader": "^1.7.1", "html-webpack-plugin": "^3.2.0", "identity-obj-proxy": "^3.0.0", + "jotai": "2.8.0", "jsdom": "^16.4.0", "lost": "^8.3.1", "madge": "^3.6.0", diff --git a/performance-metrics/Makefile b/performance-metrics/Makefile index cce4fd7d93a..fd4dd421ad2 100644 --- a/performance-metrics/Makefile +++ b/performance-metrics/Makefile @@ -25,4 +25,8 @@ clean: .PHONY: wheel wheel: $(python) setup.py $(wheel_opts) bdist_wheel - rm -rf build \ No newline at end of file + rm -rf build + +.PHONY: test +test: + $(pytest) tests \ No newline at end of file diff --git a/performance-metrics/Pipfile b/performance-metrics/Pipfile index df5a3de89d6..a71db703e33 100644 --- a/performance-metrics/Pipfile +++ b/performance-metrics/Pipfile @@ -5,15 +5,17 @@ name = "pypi" [packages] opentrons-shared-data = {file = "../shared-data/python", editable = true} +performance-metrics = {file = ".", editable = true} [dev-packages] -pytest = "==7.2.2" +pytest = "==7.4.4" mypy = "==1.8.0" flake8 = "==7.0.0" flake8-annotations = "~=3.0.1" flake8-docstrings = "~=1.7.0" flake8-noqa = "~=1.4.0" black = "==22.3.0" +pytest-asyncio = "~=0.23.0" [requires] python_version = "3.10" diff --git a/performance-metrics/Pipfile.lock b/performance-metrics/Pipfile.lock index 61556f3dee9..5c836231b7e 100644 --- a/performance-metrics/Pipfile.lock +++ b/performance-metrics/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "fa95804888e2d45ce401c98bafc9b543cb6e1afe0a36713660d3f5517ac02b8e" + "sha256": "d811fa2b7dca8a5be8b2dba79ab7200243b2e10fb65f9ee221623f2710b24372" }, "pipfile-spec": 6, "requires": { @@ -37,6 +37,10 @@ "file": "../shared-data/python", "markers": "python_version >= '3.8'" }, + "performance-metrics": { + "editable": true, + "file": "." + }, "pydantic": { "hashes": [ "sha256:005655cabc29081de8243126e036f2065bd7ea5b9dff95fde6d2c642d39755de", @@ -333,12 +337,21 @@ }, "pytest": { "hashes": [ - "sha256:130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e", - "sha256:c99ab0c73aceb050f68929bc93af19ab6db0558791c6a0715723abe9d0ade9d4" + "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280", + "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==7.2.2" + "version": "==7.4.4" + }, + "pytest-asyncio": { + "hashes": [ + "sha256:68516fdd1018ac57b846c9846b954f0393b26f094764a28c955eabb0536a4e8a", + "sha256:ffe523a89c1c222598c76856e76852b787504ddb72dd5d9b6617ffa8aa2cde5f" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==0.23.6" }, "snowballstemmer": { "hashes": [ diff --git a/performance-metrics/src/performance_metrics/__init__.py b/performance-metrics/src/performance_metrics/__init__.py index a92b39b6d7b..b5f2e760c19 100644 --- a/performance-metrics/src/performance_metrics/__init__.py +++ b/performance-metrics/src/performance_metrics/__init__.py @@ -1 +1,5 @@ """Opentrons performance metrics library.""" + +from .robot_context_tracker import RobotContextTracker + +__all__ = ["RobotContextTracker"] diff --git a/performance-metrics/src/performance_metrics/datashapes.py b/performance-metrics/src/performance_metrics/datashapes.py new file mode 100644 index 00000000000..d97d51fcb2a --- /dev/null +++ b/performance-metrics/src/performance_metrics/datashapes.py @@ -0,0 +1,63 @@ +"""Defines the shape of stored data.""" + +import dataclasses +from typing import Sequence, Tuple, Protocol, Union +from opentrons_shared_data.performance.dev_types import RobotContextState + +StorableData = Union[int, float, str] + + +class SupportsCSVStorage(Protocol): + """A protocol for classes that support CSV storage.""" + + @classmethod + def headers(self) -> Tuple[str, ...]: + """Returns the headers for the CSV data.""" + ... + + def csv_row(self) -> Tuple[StorableData, ...]: + """Returns the object as a CSV row.""" + ... + + @classmethod + def from_csv_row(cls, row: Tuple[StorableData, ...]) -> "SupportsCSVStorage": + """Returns an object from a CSV row.""" + ... + + +@dataclasses.dataclass(frozen=True) +class RawContextData(SupportsCSVStorage): + """Represents raw duration data with context state information. + + Attributes: + - function_start_time (int): The start time of the function. + - duration_measurement_start_time (int): The start time for duration measurement. + - duration_measurement_end_time (int): The end time for duration measurement. + - state (RobotContextStates): The current state of the context. + """ + + state: RobotContextState + func_start: int + duration: int + + @classmethod + def headers(self) -> Tuple[str, str, str]: + """Returns the headers for the raw context data.""" + return ("state_id", "function_start_time", "duration") + + def csv_row(self) -> Tuple[int, int, int]: + """Returns the raw context data as a string.""" + return ( + self.state.state_id, + self.func_start, + self.duration, + ) + + @classmethod + def from_csv_row(cls, row: Sequence[StorableData]) -> SupportsCSVStorage: + """Returns a RawContextData object from a CSV row.""" + return cls( + state=RobotContextState.from_id(int(row[0])), + func_start=int(row[1]), + duration=int(row[2]), + ) diff --git a/performance-metrics/src/performance_metrics/metrics_store.py b/performance-metrics/src/performance_metrics/metrics_store.py new file mode 100644 index 00000000000..49793a34cae --- /dev/null +++ b/performance-metrics/src/performance_metrics/metrics_store.py @@ -0,0 +1,37 @@ +"""Interface for storing performance metrics data to a CSV file.""" + +import csv +import typing +from opentrons_shared_data.performance.dev_types import MetricsMetadata +from performance_metrics.datashapes import SupportsCSVStorage + +T = typing.TypeVar("T", bound=SupportsCSVStorage) + + +class MetricsStore(typing.Generic[T]): + """Dataclass to store data for tracking robot context.""" + + def __init__(self, metadata: MetricsMetadata) -> None: + """Initialize the metrics store.""" + self.metadata = metadata + self._data: typing.List[T] = [] + + def add(self, context_data: T) -> None: + """Add data to the store.""" + self._data.append(context_data) + + def setup(self) -> None: + """Set up the data store.""" + self.metadata.storage_dir.mkdir(parents=True, exist_ok=True) + self.metadata.data_file_location.touch(exist_ok=True) + self.metadata.headers_file_location.touch(exist_ok=True) + self.metadata.headers_file_location.write_text(",".join(self.metadata.headers)) + + def store(self) -> None: + """Clear the stored data and write it to the storage file.""" + stored_data = self._data.copy() + self._data.clear() + rows_to_write = [context_data.csv_row() for context_data in stored_data] + with open(self.metadata.data_file_location, "a") as storage_file: + writer = csv.writer(storage_file) + writer.writerows(rows_to_write) diff --git a/performance-metrics/src/performance_metrics/robot_context_tracker.py b/performance-metrics/src/performance_metrics/robot_context_tracker.py new file mode 100644 index 00000000000..a6472bd8959 --- /dev/null +++ b/performance-metrics/src/performance_metrics/robot_context_tracker.py @@ -0,0 +1,105 @@ +"""Module for tracking robot context and execution duration for different operations.""" + +from pathlib import Path +import platform + +from functools import wraps, partial +from time import perf_counter_ns +from typing import Callable, TypeVar, cast, Literal, Final + + +from typing_extensions import ParamSpec +from performance_metrics.datashapes import ( + RawContextData, +) +from performance_metrics.metrics_store import MetricsStore +from opentrons_shared_data.performance.dev_types import ( + RobotContextState, + SupportsTracking, + MetricsMetadata, +) + +P = ParamSpec("P") +R = TypeVar("R") + + +def _get_timing_function() -> Callable[[], int]: + """Returns a timing function for the current platform.""" + time_function: Callable[[], int] + if platform.system() == "Linux": + from time import clock_gettime_ns, CLOCK_REALTIME + + time_function = cast( + Callable[[], int], partial(clock_gettime_ns, CLOCK_REALTIME) + ) + else: + from time import time_ns + + time_function = time_ns + + return time_function + + +timing_function = _get_timing_function() + + +class RobotContextTracker(SupportsTracking): + """Tracks and stores robot context and execution duration for different operations.""" + + METADATA_NAME: Final[Literal["robot_context_data"]] = "robot_context_data" + + def __init__(self, storage_location: Path, should_track: bool = False) -> None: + """Initializes the RobotContextTracker with an empty storage list.""" + self._store = MetricsStore[RawContextData]( + MetricsMetadata( + name=self.METADATA_NAME, + storage_dir=storage_location, + headers=RawContextData.headers(), + ) + ) + self._should_track = should_track + + if self._should_track: + self._store.setup() + + def track(self, state: RobotContextState) -> Callable: # type: ignore + """Decorator factory for tracking the execution duration and state of robot operations. + + Args: + state: The state to track for the decorated function. + + Returns: + Callable: A decorator that wraps a function to track its execution duration and state. + """ + + def inner_decorator(func: Callable[P, R]) -> Callable[P, R]: + if not self._should_track: + return func + + @wraps(func) + def wrapper(*args: P.args, **kwargs: P.kwargs) -> R: + function_start_time = timing_function() + duration_start_time = perf_counter_ns() + try: + result = func(*args, **kwargs) + finally: + duration_end_time = perf_counter_ns() + self._store.add( + RawContextData( + func_start=function_start_time, + duration=duration_end_time - duration_start_time, + state=state, + ) + ) + + return result + + return wrapper + + return inner_decorator + + def store(self) -> None: + """Returns the stored context data and clears the storage list.""" + if not self._should_track: + return + self._store.store() diff --git a/performance-metrics/tests/performance_metrics/test_metrics_store.py b/performance-metrics/tests/performance_metrics/test_metrics_store.py new file mode 100644 index 00000000000..ea58afc6388 --- /dev/null +++ b/performance-metrics/tests/performance_metrics/test_metrics_store.py @@ -0,0 +1,52 @@ +"""Tests for the metrics store.""" + +from pathlib import Path +from time import sleep + +from opentrons_shared_data.performance.dev_types import RobotContextState +from performance_metrics.datashapes import RawContextData +from performance_metrics.robot_context_tracker import RobotContextTracker + +# Corrected times in seconds +STARTING_TIME = 0.001 +CALIBRATING_TIME = 0.002 +ANALYZING_TIME = 0.003 +RUNNING_TIME = 0.004 +SHUTTING_DOWN_TIME = 0.005 + + +async def test_storing_to_file(tmp_path: Path) -> None: + """Tests storing the tracked data to a file.""" + robot_context_tracker = RobotContextTracker(tmp_path, should_track=True) + + @robot_context_tracker.track(state=RobotContextState.STARTING_UP) + def starting_robot() -> None: + sleep(STARTING_TIME) + + @robot_context_tracker.track(state=RobotContextState.CALIBRATING) + def calibrating_robot() -> None: + sleep(CALIBRATING_TIME) + + @robot_context_tracker.track(state=RobotContextState.ANALYZING_PROTOCOL) + def analyzing_protocol() -> None: + sleep(ANALYZING_TIME) + + starting_robot() + calibrating_robot() + analyzing_protocol() + + robot_context_tracker.store() + + with open(robot_context_tracker._store.metadata.data_file_location, "r") as file: + lines = file.readlines() + assert len(lines) == 3, "All stored data should be written to the file." + + split_lines: list[list[str]] = [line.strip().split(",") for line in lines] + assert all( + RawContextData.from_csv_row(line) for line in split_lines + ), "All lines should be valid RawContextData instances." + + with open(robot_context_tracker._store.metadata.headers_file_location, "r") as file: + headers = file.readlines() + assert len(headers) == 1, "Header should be written to the headers file." + assert tuple(headers[0].strip().split(",")) == RawContextData.headers() diff --git a/performance-metrics/tests/performance_metrics/test_robot_context_tracker.py b/performance-metrics/tests/performance_metrics/test_robot_context_tracker.py new file mode 100644 index 00000000000..1d26b87cb2e --- /dev/null +++ b/performance-metrics/tests/performance_metrics/test_robot_context_tracker.py @@ -0,0 +1,271 @@ +"""Tests for the RobotContextTracker class in performance_metrics.robot_context_tracker.""" + +import asyncio +from pathlib import Path +import pytest +from performance_metrics.robot_context_tracker import RobotContextTracker +from opentrons_shared_data.performance.dev_types import RobotContextState +from time import sleep, time_ns +from unittest.mock import patch + +# Corrected times in seconds +STARTING_TIME = 0.001 +CALIBRATING_TIME = 0.002 +ANALYZING_TIME = 0.003 +RUNNING_TIME = 0.004 +SHUTTING_DOWN_TIME = 0.005 + + +@pytest.fixture +def robot_context_tracker(tmp_path: Path) -> RobotContextTracker: + """Fixture to provide a fresh instance of RobotContextTracker for each test.""" + return RobotContextTracker(storage_location=tmp_path, should_track=True) + + +def test_robot_context_tracker(robot_context_tracker: RobotContextTracker) -> None: + """Tests the tracking of various robot context states through RobotContextTracker.""" + + @robot_context_tracker.track(state=RobotContextState.STARTING_UP) + def starting_robot() -> None: + sleep(STARTING_TIME) + + @robot_context_tracker.track(state=RobotContextState.CALIBRATING) + def calibrating_robot() -> None: + sleep(CALIBRATING_TIME) + + @robot_context_tracker.track(state=RobotContextState.ANALYZING_PROTOCOL) + def analyzing_protocol() -> None: + sleep(ANALYZING_TIME) + + @robot_context_tracker.track(state=RobotContextState.RUNNING_PROTOCOL) + def running_protocol() -> None: + sleep(RUNNING_TIME) + + @robot_context_tracker.track(state=RobotContextState.SHUTTING_DOWN) + def shutting_down_robot() -> None: + sleep(SHUTTING_DOWN_TIME) + + # Ensure storage is initially empty + assert ( + len(robot_context_tracker._store._data) == 0 + ), "Storage should be initially empty." + + starting_robot() + calibrating_robot() + analyzing_protocol() + running_protocol() + shutting_down_robot() + + # Verify that all states were tracked + assert len(robot_context_tracker._store._data) == 5, "All states should be tracked." + + # Validate the sequence and accuracy of tracked states + expected_states = [ + RobotContextState.STARTING_UP, + RobotContextState.CALIBRATING, + RobotContextState.ANALYZING_PROTOCOL, + RobotContextState.RUNNING_PROTOCOL, + RobotContextState.SHUTTING_DOWN, + ] + for i, state in enumerate(expected_states): + assert ( + RobotContextState.from_id( + robot_context_tracker._store._data[i].state.state_id + ) + == state + ), f"State at index {i} should be {state}." + + +def test_multiple_operations_single_state( + robot_context_tracker: RobotContextTracker, +) -> None: + """Tests tracking multiple operations within a single robot context state.""" + + @robot_context_tracker.track(state=RobotContextState.RUNNING_PROTOCOL) + def first_operation() -> None: + sleep(RUNNING_TIME) + + @robot_context_tracker.track(state=RobotContextState.RUNNING_PROTOCOL) + def second_operation() -> None: + sleep(RUNNING_TIME) + + first_operation() + second_operation() + + assert ( + len(robot_context_tracker._store._data) == 2 + ), "Both operations should be tracked." + assert ( + robot_context_tracker._store._data[0].state + == robot_context_tracker._store._data[1].state + == RobotContextState.RUNNING_PROTOCOL + ), "Both operations should have the same state." + + +def test_exception_handling_in_tracked_function( + robot_context_tracker: RobotContextTracker, +) -> None: + """Ensures exceptions in tracked operations are handled correctly.""" + + @robot_context_tracker.track(state=RobotContextState.SHUTTING_DOWN) + def error_prone_operation() -> None: + sleep(SHUTTING_DOWN_TIME) + raise RuntimeError("Simulated operation failure") + + with pytest.raises(RuntimeError): + error_prone_operation() + + assert ( + len(robot_context_tracker._store._data) == 1 + ), "Failed operation should still be tracked." + assert ( + robot_context_tracker._store._data[0].state == RobotContextState.SHUTTING_DOWN + ), "State should be correctly logged despite the exception." + + +@pytest.mark.asyncio +async def test_async_operation_tracking( + robot_context_tracker: RobotContextTracker, +) -> None: + """Tests tracking of an asynchronous operation.""" + + @robot_context_tracker.track(state=RobotContextState.ANALYZING_PROTOCOL) + async def async_analyzing_operation() -> None: + await asyncio.sleep(ANALYZING_TIME) + + await async_analyzing_operation() + + assert ( + len(robot_context_tracker._store._data) == 1 + ), "Async operation should be tracked." + assert ( + robot_context_tracker._store._data[0].state + == RobotContextState.ANALYZING_PROTOCOL + ), "State should be ANALYZING_PROTOCOL." + + +def test_sync_operation_timing_accuracy( + robot_context_tracker: RobotContextTracker, +) -> None: + """Tests the timing accuracy of a synchronous operation tracking.""" + + @robot_context_tracker.track(state=RobotContextState.RUNNING_PROTOCOL) + def running_operation() -> None: + sleep(RUNNING_TIME) + + running_operation() + + duration_data = robot_context_tracker._store._data[0] + assert ( + abs(duration_data.duration - RUNNING_TIME * 1e9) < 1e7 + ), "Measured duration for sync operation should closely match the expected duration." + + +@pytest.mark.asyncio +async def test_async_operation_timing_accuracy( + robot_context_tracker: RobotContextTracker, +) -> None: + """Tests the timing accuracy of an async operation tracking.""" + + @robot_context_tracker.track(state=RobotContextState.RUNNING_PROTOCOL) + async def async_running_operation() -> None: + await asyncio.sleep(RUNNING_TIME) + + await async_running_operation() + + duration_data = robot_context_tracker._store._data[0] + assert ( + abs(duration_data.duration - RUNNING_TIME * 1e9) < 1e7 + ), "Measured duration for async operation should closely match the expected duration." + + +@pytest.mark.asyncio +async def test_exception_in_async_operation( + robot_context_tracker: RobotContextTracker, +) -> None: + """Ensures exceptions in tracked async operations are correctly handled.""" + + @robot_context_tracker.track(state=RobotContextState.SHUTTING_DOWN) + async def async_error_prone_operation() -> None: + await asyncio.sleep(SHUTTING_DOWN_TIME) + raise RuntimeError("Simulated async operation failure") + + with pytest.raises(RuntimeError): + await async_error_prone_operation() + + assert ( + len(robot_context_tracker._store._data) == 1 + ), "Failed async operation should still be tracked." + assert ( + robot_context_tracker._store._data[0].state == RobotContextState.SHUTTING_DOWN + ), "State should be SHUTTING_DOWN despite the exception." + + +@pytest.mark.asyncio +async def test_concurrent_async_operations( + robot_context_tracker: RobotContextTracker, +) -> None: + """Tests tracking of concurrent async operations.""" + + @robot_context_tracker.track(state=RobotContextState.CALIBRATING) + async def first_async_calibrating() -> None: + await asyncio.sleep(CALIBRATING_TIME) + + @robot_context_tracker.track(state=RobotContextState.CALIBRATING) + async def second_async_calibrating() -> None: + await asyncio.sleep(CALIBRATING_TIME) + + await asyncio.gather(first_async_calibrating(), second_async_calibrating()) + + assert ( + len(robot_context_tracker._store._data) == 2 + ), "Both concurrent async operations should be tracked." + assert all( + data.state == RobotContextState.CALIBRATING + for data in robot_context_tracker._store._data + ), "All tracked operations should be in CALIBRATING state." + + +def test_no_tracking(tmp_path: Path) -> None: + """Tests that operations are not tracked when tracking is disabled.""" + robot_context_tracker = RobotContextTracker(tmp_path, should_track=False) + + @robot_context_tracker.track(state=RobotContextState.STARTING_UP) + def operation_without_tracking() -> None: + sleep(STARTING_TIME) + + operation_without_tracking() + + assert ( + len(robot_context_tracker._store._data) == 0 + ), "Operation should not be tracked when tracking is disabled." + + +@patch( + "performance_metrics.robot_context_tracker._get_timing_function", + return_value=time_ns, +) +def test_using_non_linux_time_functions(tmp_path: Path) -> None: + """Tests tracking operations using non-Linux time functions.""" + file_path = tmp_path / "test_file.csv" + robot_context_tracker = RobotContextTracker(file_path, should_track=True) + + @robot_context_tracker.track(state=RobotContextState.STARTING_UP) + def starting_robot() -> None: + sleep(STARTING_TIME) + + @robot_context_tracker.track(state=RobotContextState.CALIBRATING) + def calibrating_robot() -> None: + sleep(CALIBRATING_TIME) + + starting_robot() + calibrating_robot() + + storage = robot_context_tracker._store._data + assert all( + data.func_start > 0 for data in storage + ), "All function start times should be greater than 0." + assert all( + data.duration > 0 for data in storage + ), "All duration times should be greater than 0." + assert len(storage) == 2, "Both operations should be tracked." diff --git a/protocol-designer/Makefile b/protocol-designer/Makefile index a81f9be53cd..14792b22b7b 100644 --- a/protocol-designer/Makefile +++ b/protocol-designer/Makefile @@ -62,7 +62,7 @@ serve: all test-e2e: concurrently --no-color --kill-others --success first --names "protocol-designer-server,protocol-designer-tests" \ "$(MAKE) dev CYPRESS=1" \ - "wait-on http://localhost:5173/ && cypress run --browser chrome --headless --record false" + "wait-on http://localhost:5178/ && cypress run --browser chrome --headless --record false" .PHONY: test test: diff --git a/protocol-designer/cypress.config.js b/protocol-designer/cypress.config.js new file mode 100644 index 00000000000..98d139cdcbc --- /dev/null +++ b/protocol-designer/cypress.config.js @@ -0,0 +1,15 @@ +const { defineConfig } = require('cypress') + +module.exports = defineConfig({ + video: false, + viewportWidth: 1440, + viewportHeight: 900, + e2e: { + // We've imported your old cypress plugins here. + // You may want to clean this up later by importing these. + setupNodeEvents(on, config) { + return require('./cypress/plugins/index.js')(on, config) + }, + baseUrl: 'http://localhost:5178', + }, +}) diff --git a/protocol-designer/cypress.json b/protocol-designer/cypress.json deleted file mode 100644 index fa95795bfd6..00000000000 --- a/protocol-designer/cypress.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "baseUrl": "http://localhost:5173", - "video": false, - "viewportWidth": 1440, - "viewportHeight": 900, - "pluginsFile": false -} diff --git a/protocol-designer/cypress/integration/batchEdit.spec.js b/protocol-designer/cypress/e2e/batchEdit.cy.js similarity index 100% rename from protocol-designer/cypress/integration/batchEdit.spec.js rename to protocol-designer/cypress/e2e/batchEdit.cy.js diff --git a/protocol-designer/cypress/integration/home.spec.js b/protocol-designer/cypress/e2e/home.cy.js similarity index 100% rename from protocol-designer/cypress/integration/home.spec.js rename to protocol-designer/cypress/e2e/home.cy.js diff --git a/protocol-designer/cypress/integration/migrations.spec.js b/protocol-designer/cypress/e2e/migrations.cy.js similarity index 91% rename from protocol-designer/cypress/integration/migrations.spec.js rename to protocol-designer/cypress/e2e/migrations.cy.js index 6c1d01a0ee7..08fd71b7206 100644 --- a/protocol-designer/cypress/integration/migrations.spec.js +++ b/protocol-designer/cypress/e2e/migrations.cy.js @@ -26,7 +26,7 @@ describe('Protocol fixtures migrate and match snapshots', () => { expectedExportFixture: '../../fixtures/protocol/8/doItAllV3MigratedToV8.json', unusedPipettes: false, - migrationModal: 'v8', + migrationModal: 'v8.1', }, { title: 'doItAllV4 (schema 4, PD version 4.0.0) -> PD 8.1.x, schema 8', @@ -34,7 +34,7 @@ describe('Protocol fixtures migrate and match snapshots', () => { expectedExportFixture: '../../fixtures/protocol/8/doItAllV4MigratedToV8.json', unusedPipettes: false, - migrationModal: 'v8', + migrationModal: 'v8.1', }, { title: @@ -43,7 +43,7 @@ describe('Protocol fixtures migrate and match snapshots', () => { expectedExportFixture: '../../fixtures/protocol/8/doItAllV7MigratedToV8.json', unusedPipettes: false, - migrationModal: 'v8', + migrationModal: 'v8.1', }, { title: @@ -63,6 +63,16 @@ describe('Protocol fixtures migrate and match snapshots', () => { migrationModal: null, unusedPipettes: false, }, + { + title: + 'new advanced settings with multi temp => reimported, should not migrate and stay at 8.1.x, schema 8', + importFixture: + '../../fixtures/protocol/8/newAdvancedSettingsAndMultiTemp.json', + expectedExportFixture: + '../../fixtures/protocol/8/newAdvancedSettingsAndMultiTemp.json', + migrationModal: null, + unusedPipettes: false, + }, ] testCases.forEach( @@ -93,9 +103,11 @@ describe('Protocol fixtures migrate and match snapshots', () => { }) if (migrationModal) { - if (migrationModal === 'v8') { + if (migrationModal === 'v8.1') { cy.get('div') - .contains('Protocol Designer no longer supports aspirate or mix') + .contains( + 'The default dispense height is now 1mm from the bottom of the well' + ) .should('exist') cy.get('button').contains('ok', { matchCase: false }).click() } else if (migrationModal === 'newLabwareDefs') { @@ -127,7 +139,7 @@ describe('Protocol fixtures migrate and match snapshots', () => { cy.get('div') .contains( - 'This protocol can only run on app and robot server version 7.1 or higher' + 'This protocol can only run on app and robot server version 7.3.0 or higher' ) .should('exist') cy.get('button').contains('continue', { matchCase: false }).click() diff --git a/protocol-designer/cypress/integration/mixSettings.spec.js b/protocol-designer/cypress/e2e/mixSettings.cy.js similarity index 92% rename from protocol-designer/cypress/integration/mixSettings.spec.js rename to protocol-designer/cypress/e2e/mixSettings.cy.js index 60fabb65d78..c4cee578f4b 100644 --- a/protocol-designer/cypress/integration/mixSettings.spec.js +++ b/protocol-designer/cypress/e2e/mixSettings.cy.js @@ -45,7 +45,8 @@ describe('Advanced Settings for Mix Form', () => { importProtocol() openDesignTab() }) - it('Verify functionality of mix settings with different labware', () => { + it('should verify the batch edit form works as expected', () => { + // Verify functionality of mix settings with different labware enterBatchEdit() // Different labware disbales aspirate and dispense Flowrate , tipPosition, delay and touchTip @@ -74,8 +75,8 @@ describe('Advanced Settings for Mix Form', () => { // Exit batch edit mode cy.get('button').contains('exit batch edit').click() - }) - it('Verify functionality of mix settings with same labware', () => { + + // Verify functionality of mix settings with same labware enterBatchEdit() // Same labware enables aspirate and dispense Flowrate ,tipPosition ,delay and touchTip @@ -102,8 +103,8 @@ describe('Advanced Settings for Mix Form', () => { // Exit batch edit mode cy.get('button').contains('exit batch edit').click() - }) - it('verify invalid input in delay field', () => { + + // Verify invalid input in delay field // click on step 2 in batch edit mode cy.get('[data-test="StepItem_2"]').click(batchEditClickOptions) @@ -117,15 +118,14 @@ describe('Advanced Settings for Mix Form', () => { // Exit batch edit mode cy.get('button').contains('exit batch edit').click() - }) - it('verify indeterminate state of flowrate', () => { + // Verify indeterminate state of flowrate // click on step 2 in batch edit mode cy.get('[data-test="StepItem_2"]').click(batchEditClickOptions) cy.get('input[name="aspirate_flowRate"]').click({ force: true }) cy.contains( - 'Our default aspirate speed is optimal for a P1000 Single-Channel GEN2 aspirating liquids with a viscosity similar to water' + 'The default P1000 Single-Channel GEN2 flow rate is optimal for handling aqueous liquids' ) cy.get('input[name="aspirate_flowRate_customFlowRate"]').type('100') cy.get('button').contains('Done').click() @@ -138,13 +138,12 @@ describe('Advanced Settings for Mix Form', () => { // indeterminate state in flowrate is empty cy.get('input[name="aspirate_flowRate"]').should('have.value', '') - }) - it('verify functionality of flowrate in batch edit mix form', () => { + // Verify functionality of flowrate in batch edit mix form // Batch editing the Flowrate value cy.get('input[name="aspirate_flowRate"]').click({ force: true }) cy.contains( - 'Our default aspirate speed is optimal for a P1000 Single-Channel GEN2 aspirating liquids with a viscosity similar to water' + 'The default P1000 Single-Channel GEN2 flow rate is optimal for handling aqueous liquids' ) cy.get('input[name="aspirate_flowRate_customFlowRate"]').type('100') cy.get('button').contains('Done').click() @@ -168,9 +167,8 @@ describe('Advanced Settings for Mix Form', () => { // Verify that flowrate value cy.get('input[name="aspirate_flowRate"]').should('have.value', 100) - }) - it('verify delay settings indeterminate value', () => { + // Verify delay settings indeterminate value // Click on step 2, to enter batch edit mode cy.get('[data-test="StepItem_2"]').click(batchEditClickOptions) // Select delay settings @@ -190,9 +188,8 @@ describe('Advanced Settings for Mix Form', () => { ) // Exit batch edit mode cy.get('button').contains('exit batch edit').click() - }) - it('verify delay settings batch editing in mix form', () => { + // Verify delay settings batch editing in mix form // Click on step 1, to enter batch edit mode cy.get('[data-test="StepItem_1"]').click(batchEditClickOptions) // Click on step 2 to batch edit mix settings @@ -219,9 +216,8 @@ describe('Advanced Settings for Mix Form', () => { // Verify that volume is set to 2 cy.get('input[name="aspirate_delay_seconds"]').should('have.value', 2) - }) - it('verify touchTip settings indeterminate value', () => { + // Verify touchTip settings indeterminate value cy.get('[data-test="StepItem_2"]').click() // Click on step 2, to enter batch edit mode cy.get('[data-test="StepItem_2"]').click(batchEditClickOptions) @@ -241,9 +237,8 @@ describe('Advanced Settings for Mix Form', () => { ) // Exit batch edit mode cy.get('button').contains('exit batch edit').click() - }) - it('verify touchTip settings batch editing in mix form', () => { + // Verify touchTip settings batch editing in mix form cy.get('[data-test="StepItem_2"]').click() // Click on step 2, to enter batch edit mode cy.get('[data-test="StepItem_2"]').click(batchEditClickOptions) @@ -275,9 +270,8 @@ describe('Advanced Settings for Mix Form', () => { 'have.value', 16.4 ) - }) - it('verify blowout settings indeterminate value', () => { + // Verify blowout settings indeterminate value // Click on step 2, to enter batch edit mode cy.get('[data-test="StepItem_2"]').click(batchEditClickOptions) // Select blowout settings @@ -295,9 +289,8 @@ describe('Advanced Settings for Mix Form', () => { ) // Exit batch edit mode cy.get('button').contains('exit batch edit').click() - }) - it('verify blowout settings batch editing in mix form', () => { + // Verify blowout settings batch editing in mix form // Click on step 2, to enter batch edit mode cy.get('[data-test="StepItem_2"]').click(batchEditClickOptions) // Click on step 3 to batch edit mix settings @@ -329,9 +322,8 @@ describe('Advanced Settings for Mix Form', () => { const expectedSubstring = 'trashBin' expect(value).to.include(expectedSubstring) }) - }) - it('verify well-order indeterminate state', () => { + // verify well-order indeterminate state // Click on step 2, to enter batch edit and click on well order to change the order cy.get('[data-test="StepItem_2"]').click(batchEditClickOptions) // click on well-order and change the order diff --git a/protocol-designer/cypress/integration/settings.spec.js b/protocol-designer/cypress/e2e/settings.cy.js similarity index 85% rename from protocol-designer/cypress/integration/settings.spec.js rename to protocol-designer/cypress/e2e/settings.cy.js index 3f248d79ab0..f2bb737be50 100644 --- a/protocol-designer/cypress/integration/settings.spec.js +++ b/protocol-designer/cypress/e2e/settings.cy.js @@ -5,32 +5,27 @@ describe('The Settings Page', () => { cy.visit('/') }) - it('displays the announcement modal and clicks "GOT IT!" to close it', () => { + it('Verify the settings page', () => { + // displays the announcement modal and clicks "GOT IT!" to close it cy.closeAnnouncementModal() - }) - it('contains a working settings button', () => { + // contains a working settings button cy.openSettingsPage() cy.contains('App Settings') - }) - it('contains an information section', () => { + // contains an information section cy.get('h3').contains('Information').should('exist') - }) - it('contains version information', () => { + // contains version information cy.contains('Protocol Designer Version').should('exist') - }) - it('contains a hints section', () => { + // contains a hints section cy.get('h3').contains('Hints').should('exist') - }) - it('contains a privacy section', () => { + // contains a privacy section cy.get('h3').contains('Privacy').should('exist') - }) - it('contains a share settings button in the pivacy section', () => { + // contains a share settings button in the pivacy section // It's toggled off by default cy.contains('Share sessions') .next() @@ -50,13 +45,11 @@ describe('The Settings Page', () => { .next() .should('have.attr', 'class') .and('match', /toggled_off/) - }) - it('contains an experimental settings section', () => { + // contains an experimental settings section cy.get('h3').contains('Experimental Settings').should('exist') - }) - it("contains a 'disable module placement restrictions' experimental feature", () => { + // contains a 'disable module placement restrictions' experimental feature // It's toggled off by default cy.contains(exptlSettingText) .next() @@ -93,9 +86,8 @@ describe('The Settings Page', () => { .next() .should('have.attr', 'class') .and('match', /toggled_off/) - }) - it("contains a 'disable module placement restrictions' toggle in the experimental settings card", () => { + // contains a 'disable module placement restrictions' toggle in the experimental settings card // It's toggled off by default cy.contains('Disable module') .next() @@ -131,9 +123,8 @@ describe('The Settings Page', () => { .next() .should('have.attr', 'class') .and('match', /toggled_off/) - }) - it('remembers when we enable things', () => { + // PD remembers when we enable things // Enable a button // We're not using the privacy button because that // interacts with analytics libraries, which might @@ -149,9 +140,8 @@ describe('The Settings Page', () => { .next() .should('have.attr', 'class') .and('match', /toggled_on/) - }) - it('remembers when we disable things', () => { + // PD remembers when we disable things // Disable a button // We're not using the privacy button because that // interacts with analytics libraries, which might diff --git a/protocol-designer/cypress/integration/sidebar.spec.js b/protocol-designer/cypress/e2e/sidebar.cy.js similarity index 100% rename from protocol-designer/cypress/integration/sidebar.spec.js rename to protocol-designer/cypress/e2e/sidebar.cy.js diff --git a/protocol-designer/cypress/integration/transferSettings.spec.js b/protocol-designer/cypress/e2e/transferSettings.cy.js similarity index 92% rename from protocol-designer/cypress/integration/transferSettings.spec.js rename to protocol-designer/cypress/e2e/transferSettings.cy.js index 82fa26f8dae..286bc2cb377 100644 --- a/protocol-designer/cypress/integration/transferSettings.spec.js +++ b/protocol-designer/cypress/e2e/transferSettings.cy.js @@ -50,7 +50,9 @@ describe('Advanced Settings for Transfer Form', () => { openDesignTab() }) - it('Verify functionality of advanced settings with different pipette and labware', () => { + it('Verify functionality of the transfer form', () => { + // Verify functionality of advanced settings with different pipette and labware + enterBatchEdit() // Different Pipette disables aspirate and dispense Flowrate and Mix settings @@ -88,9 +90,9 @@ describe('Advanced Settings for Transfer Form', () => { // Exit batch edit mode cy.get('button').contains('exit batch edit').click() - }) - it('Verify functionality of advanced settings with same pipette and labware', () => { + // Verify functionality of advanced settings with same pipette and labware + // click on step 2 in batch edit mode cy.get('[data-test="StepItem_2"]').click(batchEditClickOptions) // deselecting on step 6 in batch edit mode @@ -133,15 +135,14 @@ describe('Advanced Settings for Transfer Form', () => { // Exit batch edit mode cy.get('button').contains('exit batch edit').click() - }) - it('verify flowrate indeterminate value', () => { + // Verify flowrate indeterminate value // click on step 2 in batch edit mode cy.get('[data-test="StepItem_2"]').click(batchEditClickOptions) cy.get('input[name="aspirate_flowRate"]').click({ force: true }) cy.contains( - 'Our default aspirate speed is optimal for a P1000 Single-Channel GEN2 aspirating liquids with a viscosity similar to water' + 'The default P1000 Single-Channel GEN2 flow rate is optimal for handling aqueous liquids' ) cy.get('input[name="aspirate_flowRate_customFlowRate"]').type('100') cy.get('button').contains('Done').click() @@ -154,13 +155,13 @@ describe('Advanced Settings for Transfer Form', () => { // indeterminate state in flowrate is empty cy.get('input[name="aspirate_flowRate"]').should('have.value', '') - }) - it('verify functionality of flowrate in batch edit transfer', () => { + // Verify functionality of flowrate in batch edit transfer + // Batch editing the Flowrate value cy.get('input[name="aspirate_flowRate"]').click({ force: true }) cy.contains( - 'Our default aspirate speed is optimal for a P1000 Single-Channel GEN2 aspirating liquids with a viscosity similar to water' + 'The default P1000 Single-Channel GEN2 flow rate is optimal for handling aqueous liquids' ) cy.get('input[name="aspirate_flowRate_customFlowRate"]').type('100') cy.get('button').contains('Done').click() @@ -184,14 +185,13 @@ describe('Advanced Settings for Transfer Form', () => { // Verify that flowrate value cy.get('input[name="aspirate_flowRate"]').should('have.value', 100) - }) - it('verify prewet tip indeterminate value', () => { + // Verify prewet tip indeterminate value // Click on step 2, to enter batch edit and enable prewet tip cy.get('[data-test="StepItem_2"]').click(batchEditClickOptions) // enable pre-wet tip cy.togglePreWetTip() - cy.get('input[name="preWetTip"]').should('be.visible') + cy.get('input[name="preWetTip"]').should('be.enabled') // Click save button to save the changes cy.get('button').contains('save').click() // Click on step 1, as it does not have prewet-tip selected - indeteminate state @@ -204,9 +204,9 @@ describe('Advanced Settings for Transfer Form', () => { ) // Exit batch edit mode cy.get('button').contains('exit batch edit').click() - }) - it('verify mix settings indeterminate value', () => { + // Verify mix settings indeterminate value + // Click on step 2, to enter batch edit mode cy.get('[data-test="StepItem_4"]').click(batchEditClickOptions) // Select mix settings @@ -225,9 +225,9 @@ describe('Advanced Settings for Transfer Form', () => { ) // Exit batch edit mode cy.get('button').contains('exit batch edit').click() - }) - it('verify mix settings batch editing in transfer form', () => { + // Verify mix settings batch editing in transfer form + // Click on step 2, to enter batch edit mode cy.get('[data-test="StepItem_2"]').click(batchEditClickOptions) // Click on step 3 to batch edit mix settings @@ -249,9 +249,9 @@ describe('Advanced Settings for Transfer Form', () => { // Verify that volume is set to 10 and repetitions to 2 cy.get('input[name="aspirate_mix_volume"]').should('have.value', 10) cy.get('input[name="aspirate_mix_times"]').should('have.value', 2) - }) - it('verify delay settings indeterminate value', () => { + // Verify delay settings indeterminate value + // Click on step 2, to enter batch edit mode cy.get('[data-test="StepItem_2"]').click(batchEditClickOptions) // Select delay settings @@ -271,9 +271,9 @@ describe('Advanced Settings for Transfer Form', () => { ) // Exit batch edit mode cy.get('button').contains('exit batch edit').click() - }) - it('verify delay settings batch editing in transfer form', () => { + // Verify delay settings batch editing in transfer form + // Click on step 4, to enter batch edit mode cy.get('[data-test="StepItem_4"]').click(batchEditClickOptions) // Click on step 5 to batch edit mix settings @@ -300,9 +300,9 @@ describe('Advanced Settings for Transfer Form', () => { // Verify that volume is set to 2 and repitions to 2 cy.get('input[name="aspirate_delay_seconds"]').should('have.value', 2) - }) - it('verify touchTip settings indeterminate value', () => { + // Verify touchTip settings indeterminate value + cy.get('[data-test="StepItem_2"]').click() // Click on step 2, to enter batch edit mode cy.get('[data-test="StepItem_2"]').click(batchEditClickOptions) @@ -322,9 +322,9 @@ describe('Advanced Settings for Transfer Form', () => { ) // Exit batch edit mode cy.get('button').contains('exit batch edit').click() - }) - it('verify touchTip settings batch editing in transfer form', () => { + // verify touchTip settings batch editing in transfer form + // Click on step 2, to enter batch edit mode cy.get('[data-test="StepItem_2"]').click(batchEditClickOptions) // Click on step 3 to batch edit mix settings @@ -355,9 +355,8 @@ describe('Advanced Settings for Transfer Form', () => { 'have.value', 13.78 ) - }) - it('verify blowout settings indeterminate value', () => { + // verify blowout settings indeterminate value // Click on step 2, to enter batch edit mode cy.get('[data-test="StepItem_2"]').click(batchEditClickOptions) // Select blowout settings @@ -375,9 +374,9 @@ describe('Advanced Settings for Transfer Form', () => { ) // Exit batch edit mode cy.get('button').contains('exit batch edit').click() - }) - it('verify blowout settings batch editing in transfer form', () => { + // Verify blowout settings batch editing in transfer form + // Click on step 2, to enter batch edit mode cy.get('[data-test="StepItem_2"]').click(batchEditClickOptions) // Click on step 3 to batch edit mix settings diff --git a/protocol-designer/cypress/support/index.js b/protocol-designer/cypress/support/e2e.js similarity index 100% rename from protocol-designer/cypress/support/index.js rename to protocol-designer/cypress/support/e2e.js diff --git a/protocol-designer/fixtures/protocol/8/doItAllV3MigratedToV8.json b/protocol-designer/fixtures/protocol/8/doItAllV3MigratedToV8.json index e448368f932..c33b1764d40 100644 --- a/protocol-designer/fixtures/protocol/8/doItAllV3MigratedToV8.json +++ b/protocol-designer/fixtures/protocol/8/doItAllV3MigratedToV8.json @@ -6,7 +6,7 @@ "author": "Fixture", "description": "Test all v3 commands", "created": 1585930833548, - "lastModified": 1711742442671, + "lastModified": 1714570099662, "category": null, "subcategory": null, "tags": [] @@ -15,10 +15,10 @@ "name": "opentrons/protocol-designer", "version": "8.1.0", "data": { - "_internalAppBuildDate": "Fri, 29 Mar 2024 20:00:04 GMT", + "_internalAppBuildDate": "Wed, 01 May 2024 13:16:50 GMT", "defaultValues": { "aspirate_mmFromBottom": 1, - "dispense_mmFromBottom": 0.5, + "dispense_mmFromBottom": 1, "touchTip_mmFromTop": -1, "blowout_mmFromTop": 0 }, @@ -73,7 +73,7 @@ "3961e4c0-75c7-11ea-b42f-4b64e50f43e5": { "pipette": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": "40", - "tipRack": "0b44c760-75c7-11ea-b42f-4b64e50f43e5:opentrons/opentrons_96_tiprack_300ul/1", + "tipRack": "opentrons/opentrons_96_tiprack_300ul/1", "changeTip": "always", "path": "multiDispense", "aspirate_wells_grouped": false, @@ -101,7 +101,6 @@ "dispense_touchTip_mmFromBottom": 40, "disposalVolume_checkbox": true, "disposalVolume_volume": "20", - "blowout_z_offset": 0, "blowout_checkbox": false, "blowout_location": "8053a205-f2dc-4b1d-8d05-bf8233949e2e:trashBin", "preWetTip": false, @@ -121,6 +120,8 @@ "dispense_y_position": 0, "aspirate_x_position": 0, "aspirate_y_position": 0, + "blowout_z_offset": 0, + "blowout_flowRate": null, "id": "3961e4c0-75c7-11ea-b42f-4b64e50f43e5", "stepType": "moveLiquid", "stepName": "transfer", @@ -158,7 +159,6 @@ "labware": "1e610d40-75c7-11ea-b42f-4b64e50f43e5:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1", "mix_wellOrder_first": "t2b", "mix_wellOrder_second": "l2r", - "blowout_z_offset": 0, "blowout_checkbox": true, "blowout_location": "8053a205-f2dc-4b1d-8d05-bf8233949e2e:trashBin", "mix_mmFromBottom": 0.5, @@ -175,9 +175,11 @@ "mix_touchTip_mmFromBottom": 11.8, "dropTip_location": "8053a205-f2dc-4b1d-8d05-bf8233949e2e:trashBin", "nozzles": null, - "tipRack": "0b44c760-75c7-11ea-b42f-4b64e50f43e5:opentrons/opentrons_96_tiprack_300ul/1", + "tipRack": "opentrons/opentrons_96_tiprack_300ul/1", "mix_x_position": 0, "mix_y_position": 0, + "blowout_z_offset": 0, + "blowout_flowRate": 46.43, "id": "a4cee9a0-75dc-11ea-b42f-4b64e50f43e5", "stepType": "mix", "stepName": "mix", @@ -2526,7 +2528,7 @@ "commandSchemaId": "opentronsCommandSchemaV8", "commands": [ { - "key": "d371b7e2-71a8-4a60-90bc-7e865d9881b9", + "key": "5dcb42c0-ef1c-4a3b-a383-82fa21354cf8", "commandType": "loadPipette", "params": { "pipetteName": "p300_single_gen2", @@ -2535,7 +2537,7 @@ } }, { - "key": "424963b7-59f8-434a-bedc-9597e7b72c9f", + "key": "a777658d-cb9e-411c-9377-d7c965ededd2", "commandType": "loadLabware", "params": { "displayName": "Opentrons 96 Tip Rack 300 µL", @@ -2547,7 +2549,7 @@ } }, { - "key": "05ef86f7-dec0-4134-a15d-5e38ef81cf8e", + "key": "723094b7-6539-41ae-8657-225153d07ed2", "commandType": "loadLabware", "params": { "displayName": "NEST 96 Well Plate 100 µL PCR Full Skirt", @@ -2559,7 +2561,7 @@ } }, { - "key": "ddefc5ef-b69a-4172-921b-959ba5e8d8d2", + "key": "382eb174-58a8-445b-9216-67953b1431cc", "commandType": "loadLabware", "params": { "displayName": "Opentrons 24 Well Aluminum Block with Generic 2 mL Screwcap", @@ -2572,7 +2574,7 @@ }, { "commandType": "loadLiquid", - "key": "2a2084d5-67d8-4806-b919-5962a6258c1f", + "key": "a8535ce0-8b05-4dd7-b82e-ce108e7b1644", "params": { "liquidId": "0", "labwareId": "1e610d40-75c7-11ea-b42f-4b64e50f43e5:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1", @@ -2598,12 +2600,12 @@ }, { "commandType": "waitForDuration", - "key": "c1a1eff4-7ef7-46be-aee7-ebca5924ace8", + "key": "1cf744b2-f1ec-40d3-9afb-8dde33832ac4", "params": { "seconds": 62, "message": "" } }, { "commandType": "pickUpTip", - "key": "63ca0ab5-4cb6-4531-b912-1ba22e1b1a03", + "key": "8335cc6a-f1a7-42de-9085-60a58f3c099f", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "labwareId": "0b44c760-75c7-11ea-b42f-4b64e50f43e5:opentrons/opentrons_96_tiprack_300ul/1", @@ -2612,7 +2614,7 @@ }, { "commandType": "aspirate", - "key": "5ead7532-0eb2-4ad9-b704-856422fc9408", + "key": "bd82daf5-9bbd-468a-9266-3a0feb5235a7", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 30, @@ -2627,7 +2629,7 @@ }, { "commandType": "dispense", - "key": "3838f7d1-3450-49cc-a222-c8113eecf108", + "key": "02f9b8eb-ad2a-48e6-8eaf-f1446fad8bc9", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 30, @@ -2642,7 +2644,7 @@ }, { "commandType": "aspirate", - "key": "25697ae7-169d-447a-906c-4e7f02950fe9", + "key": "eab61544-7238-4479-a195-8999806e7294", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 30, @@ -2657,7 +2659,7 @@ }, { "commandType": "dispense", - "key": "49a139f4-87ba-421d-9ef4-4ebe13beb987", + "key": "deacca0e-f618-4159-bcf8-ad4d5010ffbf", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 30, @@ -2672,7 +2674,7 @@ }, { "commandType": "aspirate", - "key": "4e96faa5-c669-4b60-b15c-9d2f01c9c3fe", + "key": "296ea248-151d-4c80-9445-6678f9bbdd16", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 100, @@ -2687,7 +2689,7 @@ }, { "commandType": "touchTip", - "key": "8eff88a1-fec9-46d7-b292-f6ce378e5ad9", + "key": "93a2f17f-35e4-4585-9f32-cfbd4e80de75", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "labwareId": "1e610d40-75c7-11ea-b42f-4b64e50f43e5:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1", @@ -2697,7 +2699,7 @@ }, { "commandType": "dispense", - "key": "c95e323c-be69-4460-8acf-d1d4b74384bd", + "key": "a64de676-0aea-4dc8-a417-d1d0a7749aba", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 40, @@ -2712,7 +2714,7 @@ }, { "commandType": "touchTip", - "key": "0da25745-5e25-4138-b67c-dfc4c89c8949", + "key": "3714818d-0ea7-4b21-807c-3fc99647fcd8", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "labwareId": "21ed8f60-75c7-11ea-b42f-4b64e50f43e5:opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1", @@ -2722,7 +2724,7 @@ }, { "commandType": "dispense", - "key": "28eeb3d1-6e83-4414-8c0d-e8761ca2f75a", + "key": "8062fd11-8818-4956-958d-ca27f740d5ac", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 40, @@ -2737,7 +2739,7 @@ }, { "commandType": "touchTip", - "key": "8cd5d90d-df0b-4c3b-8cb3-cea6f1849fef", + "key": "dd3759ef-133b-49ec-94b9-20a05b4044e7", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "labwareId": "21ed8f60-75c7-11ea-b42f-4b64e50f43e5:opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1", @@ -2747,7 +2749,7 @@ }, { "commandType": "moveToAddressableArea", - "key": "35643d1f-ae0b-4a90-9de4-c9eb3c9b775e", + "key": "7b851c66-19ed-4d4e-ad2d-f8149744a720", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "addressableAreaName": "fixedTrash", @@ -2756,7 +2758,7 @@ }, { "commandType": "blowOutInPlace", - "key": "d540a57a-6968-44a0-8645-b221a9b7bfd7", + "key": "ccf8dea1-5c66-42dc-985b-91728f9d80c2", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "flowRate": 46.43 @@ -2764,7 +2766,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "c721cfd7-fef8-4fcb-9d6f-1d78f2317729", + "key": "276e3971-8910-4e53-8130-90f4bcb6f2c6", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "addressableAreaName": "fixedTrash", @@ -2774,17 +2776,17 @@ }, { "commandType": "dropTipInPlace", - "key": "a18788f3-cd5f-4470-8831-455d14883d1c", + "key": "4ba17bb2-3dbc-440e-a6ac-323eda333bdb", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5" } }, { "commandType": "waitForResume", - "key": "a54eb58b-ce5c-4a59-ba85-ed75438146a7", + "key": "6ffda031-bdb9-4b93-9749-9376f0487817", "params": { "message": "Wait until user intervention" } }, { "commandType": "pickUpTip", - "key": "c1bddcd0-d5cf-4d7c-b830-a5b27a5a71cb", + "key": "0eea0f55-ccb9-4805-89d5-f7f5069ac146", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "labwareId": "0b44c760-75c7-11ea-b42f-4b64e50f43e5:opentrons/opentrons_96_tiprack_300ul/1", @@ -2793,7 +2795,7 @@ }, { "commandType": "aspirate", - "key": "1660f6c2-9072-4348-b034-cb45712f8cd7", + "key": "6c133bc3-4f21-474d-b7a1-8dc575f05d07", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 35, @@ -2808,7 +2810,7 @@ }, { "commandType": "dispense", - "key": "c3683fde-b4e0-4432-ad96-932292f2ebcd", + "key": "927af8f8-3e17-4adc-8cf8-25e3e3b032a3", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 35, @@ -2823,7 +2825,7 @@ }, { "commandType": "aspirate", - "key": "59251222-f64d-400b-98a6-71f95f24bec7", + "key": "8a286376-d039-4868-b43a-5a4dc18a7684", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 35, @@ -2838,7 +2840,7 @@ }, { "commandType": "dispense", - "key": "a370936b-c12f-4039-88d0-97bb262cb80e", + "key": "52758061-375e-4238-a3e8-fd8d8ac7c109", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 35, @@ -2853,7 +2855,7 @@ }, { "commandType": "aspirate", - "key": "8f428646-3bd6-4a90-9674-23d3e3be8a63", + "key": "0f7bcdd1-626a-4e8a-b9de-cbe1ddcab0b5", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 35, @@ -2868,7 +2870,7 @@ }, { "commandType": "dispense", - "key": "445797f5-5799-486a-b0e2-299e2f23ca2a", + "key": "385cdb61-97e6-44a5-9bbb-d3c2a4042461", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 35, @@ -2883,7 +2885,7 @@ }, { "commandType": "moveToAddressableArea", - "key": "d740d713-a3cb-4bdb-81a5-798059db8be7", + "key": "c82f0730-3269-43ba-b7aa-bdce062fa8e1", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "addressableAreaName": "fixedTrash", @@ -2892,15 +2894,15 @@ }, { "commandType": "blowOutInPlace", - "key": "ba227a58-a0b1-4d83-93f8-4a3566cbedf1", + "key": "b04ddf2b-fd58-4c5f-bb5e-3454a593424c", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", - "flowRate": 35 + "flowRate": 46.43 } }, { "commandType": "touchTip", - "key": "68b765bb-a232-49ec-b6be-fc6b375b0a15", + "key": "8b977bb4-262a-4437-a89c-aea221051c77", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "labwareId": "1e610d40-75c7-11ea-b42f-4b64e50f43e5:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1", @@ -2910,7 +2912,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "1464952c-cb00-48eb-a9db-8a4367d3ce0b", + "key": "f6624d29-db3e-4a60-8fd9-a81d7d5e589f", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "addressableAreaName": "fixedTrash", @@ -2920,12 +2922,12 @@ }, { "commandType": "dropTipInPlace", - "key": "2d96c742-46d0-4efa-8e94-3118e975bdd4", + "key": "eab34b0e-b50f-4d4c-a7fc-2e4dfb46e95e", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5" } }, { "commandType": "pickUpTip", - "key": "75a6817c-7f41-4a8c-a184-5e6e7aad51e9", + "key": "6cd7a187-1252-4f7e-81e9-a012173a96e7", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "labwareId": "0b44c760-75c7-11ea-b42f-4b64e50f43e5:opentrons/opentrons_96_tiprack_300ul/1", @@ -2934,7 +2936,7 @@ }, { "commandType": "aspirate", - "key": "3e1db7e3-a5eb-473c-a98b-1c91e9b70c3d", + "key": "9655cd15-caff-4f78-ab83-2398146afa54", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 35, @@ -2949,7 +2951,7 @@ }, { "commandType": "dispense", - "key": "d37facff-0753-4d92-9599-93141c97a90f", + "key": "645cf76c-a1d3-4d72-82e3-29ca0bc7a68a", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 35, @@ -2964,7 +2966,7 @@ }, { "commandType": "aspirate", - "key": "df03e618-352a-44e8-8890-859f53229f10", + "key": "cf49d7f4-8175-44db-a0f6-5cc9c500ded7", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 35, @@ -2979,7 +2981,7 @@ }, { "commandType": "dispense", - "key": "0b93f43f-b456-47fa-b9d7-89086cd9c20b", + "key": "8f7c947b-43a9-439d-b8e0-dc52b5243ecc", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 35, @@ -2994,7 +2996,7 @@ }, { "commandType": "aspirate", - "key": "310303b6-76e3-4765-bd82-042eac727669", + "key": "5534b4fa-7a7e-4606-a0eb-511a08febe55", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 35, @@ -3009,7 +3011,7 @@ }, { "commandType": "dispense", - "key": "9881ac40-2932-4197-a03b-77c936651a3b", + "key": "3fedeb8a-10ed-4798-bd26-66bc4ac4faf7", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 35, @@ -3024,7 +3026,7 @@ }, { "commandType": "moveToAddressableArea", - "key": "f521a11f-1676-4dc2-a022-f5eba1c5d22e", + "key": "d4588b11-4268-40d9-aee4-312c5c1f7e3e", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "addressableAreaName": "fixedTrash", @@ -3033,15 +3035,15 @@ }, { "commandType": "blowOutInPlace", - "key": "daede461-9d74-4259-91e6-ecf7ddaa4897", + "key": "146bf039-743e-46f9-80d8-635451a2a40b", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", - "flowRate": 35 + "flowRate": 46.43 } }, { "commandType": "touchTip", - "key": "0cde152c-2aeb-4e86-9745-3732e0074ba7", + "key": "a263b140-4162-4871-a852-cae73b375e8f", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "labwareId": "1e610d40-75c7-11ea-b42f-4b64e50f43e5:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1", @@ -3051,7 +3053,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "cb24aade-655e-4f6f-83d7-1b60457b56e6", + "key": "da3d817e-fcf6-4a50-bdb7-a3e71fc71f0e", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "addressableAreaName": "fixedTrash", @@ -3061,7 +3063,7 @@ }, { "commandType": "dropTipInPlace", - "key": "6970ad16-6e47-4f5c-afba-3704abe0eabb", + "key": "30463b38-428f-460c-90bd-09f50776320c", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5" } } ], diff --git a/protocol-designer/fixtures/protocol/8/doItAllV4MigratedToV8.json b/protocol-designer/fixtures/protocol/8/doItAllV4MigratedToV8.json index f8fec2171af..5876d7bf450 100644 --- a/protocol-designer/fixtures/protocol/8/doItAllV4MigratedToV8.json +++ b/protocol-designer/fixtures/protocol/8/doItAllV4MigratedToV8.json @@ -6,7 +6,7 @@ "author": "Fixture", "description": "Test all v4 commands", "created": 1585930833548, - "lastModified": 1711742493128, + "lastModified": 1714570366192, "category": null, "subcategory": null, "tags": [] @@ -15,10 +15,10 @@ "name": "opentrons/protocol-designer", "version": "8.1.0", "data": { - "_internalAppBuildDate": "Fri, 29 Mar 2024 20:00:04 GMT", + "_internalAppBuildDate": "Wed, 01 May 2024 13:32:34 GMT", "defaultValues": { "aspirate_mmFromBottom": 1, - "dispense_mmFromBottom": 0.5, + "dispense_mmFromBottom": 1, "touchTip_mmFromTop": -1, "blowout_mmFromTop": 0 }, @@ -107,7 +107,7 @@ "3961e4c0-75c7-11ea-b42f-4b64e50f43e5": { "pipette": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": "30", - "tipRack": "0b44c760-75c7-11ea-b42f-4b64e50f43e5:opentrons/opentrons_96_tiprack_300ul/1", + "tipRack": "opentrons/opentrons_96_tiprack_300ul/1", "changeTip": "always", "path": "single", "aspirate_wells_grouped": false, @@ -135,7 +135,6 @@ "dispense_touchTip_mmFromBottom": null, "disposalVolume_checkbox": true, "disposalVolume_volume": "20", - "blowout_z_offset": 0, "blowout_checkbox": false, "blowout_location": "84882326-9cd3-428e-8352-89f133a1fe5d:trashBin", "preWetTip": false, @@ -155,6 +154,8 @@ "dispense_y_position": 0, "aspirate_x_position": 0, "aspirate_y_position": 0, + "blowout_z_offset": 0, + "blowout_flowRate": null, "id": "3961e4c0-75c7-11ea-b42f-4b64e50f43e5", "stepType": "moveLiquid", "stepName": "transfer", @@ -2551,7 +2552,7 @@ "commandSchemaId": "opentronsCommandSchemaV8", "commands": [ { - "key": "b7185c84-9b15-4b6e-a315-e331249569fa", + "key": "d99eb537-6cb6-4cd4-8331-3eeafdd4e45e", "commandType": "loadPipette", "params": { "pipetteName": "p300_single_gen2", @@ -2560,7 +2561,7 @@ } }, { - "key": "0d1f6599-70d5-4e99-9608-7d249135b5a9", + "key": "ecbb4b97-d248-4f78-a340-d412e0e87be4", "commandType": "loadModule", "params": { "model": "magneticModuleV2", @@ -2569,7 +2570,7 @@ } }, { - "key": "2ee81ffe-c8fa-4cac-be56-62a902e301f7", + "key": "c08483ea-e4a8-46a0-9533-12a340bd377a", "commandType": "loadModule", "params": { "model": "temperatureModuleV2", @@ -2578,7 +2579,7 @@ } }, { - "key": "e1da2e62-ac25-405f-b896-99384ab081d8", + "key": "8e908f00-8462-449a-b59b-8bad8a8bf655", "commandType": "loadLabware", "params": { "displayName": "Opentrons 96 Tip Rack 300 µL", @@ -2590,7 +2591,7 @@ } }, { - "key": "2895d8a7-239c-4d6b-afc8-69defe261790", + "key": "4977d62d-75a5-4a20-ae8e-8b62e88c3b0f", "commandType": "loadLabware", "params": { "displayName": "NEST 96 Well Plate 100 µL PCR Full Skirt", @@ -2604,7 +2605,7 @@ } }, { - "key": "46b84345-0c06-41f8-860d-1dfafa424e80", + "key": "d62c61f4-cdf2-4313-8183-4b6401d1c807", "commandType": "loadLabware", "params": { "displayName": "Opentrons 24 Well Aluminum Block with Generic 2 mL Screwcap", @@ -2619,7 +2620,7 @@ }, { "commandType": "loadLiquid", - "key": "25dd8768-7731-4dee-9f5a-d54b9eb0983c", + "key": "3cc4e4b7-0121-484e-af30-19b202941154", "params": { "liquidId": "0", "labwareId": "1e610d40-75c7-11ea-b42f-4b64e50f43e5:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1", @@ -2645,7 +2646,7 @@ }, { "commandType": "magneticModule/engage", - "key": "3471fe25-a3a8-4be0-b6d8-545819c4aea0", + "key": "c9af3ef4-d79b-4f75-aea9-5daf8c7b95f1", "params": { "moduleId": "0b419310-75c7-11ea-b42f-4b64e50f43e5:magneticModuleType", "height": 6 @@ -2653,7 +2654,7 @@ }, { "commandType": "temperatureModule/setTargetTemperature", - "key": "610ae127-200b-48ae-8cbc-7ba4b5ca7b30", + "key": "fb5cdf77-8b2d-430d-9d38-09556cb6fa40", "params": { "moduleId": "0b4319b0-75c7-11ea-b42f-4b64e50f43e5:temperatureModuleType", "celsius": 25 @@ -2661,12 +2662,12 @@ }, { "commandType": "waitForDuration", - "key": "94aa4488-7792-49bc-ac3d-6a260bad0f86", + "key": "5d2283e2-5f14-4c7b-a98b-a7fb464c0bb8", "params": { "seconds": 62, "message": "" } }, { "commandType": "pickUpTip", - "key": "1a838ef5-ea1a-4680-bac0-6eaf473465a4", + "key": "a9b8a288-1a4a-44b7-88c3-c6cdb4b52b89", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "labwareId": "0b44c760-75c7-11ea-b42f-4b64e50f43e5:opentrons/opentrons_96_tiprack_300ul/1", @@ -2675,7 +2676,7 @@ }, { "commandType": "aspirate", - "key": "f74c2687-f02c-4034-aa03-9a73c1ee47af", + "key": "e91dc8c3-dfda-441b-9546-0f7e8dad4882", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 30, @@ -2690,7 +2691,7 @@ }, { "commandType": "dispense", - "key": "507c7fff-1193-4c14-a0b1-e4bb9fe9d96e", + "key": "3a1820bb-4dc3-4cde-8e88-a863d9419e8a", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 30, @@ -2705,7 +2706,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "5a050ced-d1a9-4031-bf16-ed49cb561e60", + "key": "a4c10a8c-e960-430c-b5f5-f5b10c109a3a", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "addressableAreaName": "fixedTrash", @@ -2715,12 +2716,12 @@ }, { "commandType": "dropTipInPlace", - "key": "8083dcbe-8c00-4178-90c0-4d4a921bca9c", + "key": "8cd24129-b76d-4c65-95a7-b148358e0db9", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5" } }, { "commandType": "pickUpTip", - "key": "e6db98b2-7239-4f6b-9e41-02e1dd108ad6", + "key": "66a6278b-9e16-43c1-bde2-1e5c3da0e2d7", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "labwareId": "0b44c760-75c7-11ea-b42f-4b64e50f43e5:opentrons/opentrons_96_tiprack_300ul/1", @@ -2729,7 +2730,7 @@ }, { "commandType": "aspirate", - "key": "47cf3011-68e2-40cd-8563-145e460f93aa", + "key": "5a8abdb2-2ac2-4069-b010-2eaac95acece", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 30, @@ -2744,7 +2745,7 @@ }, { "commandType": "dispense", - "key": "1f1d966a-9095-4857-9137-36131c91bfd2", + "key": "58b3983a-9383-4013-8145-0a6b3398ad78", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 30, @@ -2759,7 +2760,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "ac6074f6-2f28-4012-914b-d3b28eb8453d", + "key": "a1175c8b-d19c-4e97-bad0-6ae84eb0bec5", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "addressableAreaName": "fixedTrash", @@ -2769,12 +2770,12 @@ }, { "commandType": "dropTipInPlace", - "key": "074050d3-0c4c-4fc0-8036-a5dc9afe99ef", + "key": "1457d4ac-4aee-4b32-845e-64a1025f0007", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5" } }, { "commandType": "temperatureModule/waitForTemperature", - "key": "89672a34-bd2f-4e2a-bacc-407bb5f563a1", + "key": "a22d457a-2815-43dd-9f56-a7ee53f6e628", "params": { "moduleId": "0b4319b0-75c7-11ea-b42f-4b64e50f43e5:temperatureModuleType", "celsius": 25 @@ -2782,19 +2783,19 @@ }, { "commandType": "magneticModule/disengage", - "key": "26603c88-f0a7-49b3-a65c-37e9e23ac2ff", + "key": "e07424ee-2e30-49bc-927d-dc8a4f3fc2f2", "params": { "moduleId": "0b419310-75c7-11ea-b42f-4b64e50f43e5:magneticModuleType" } }, { "commandType": "waitForResume", - "key": "f0e0a8c0-01df-47d7-92e5-c3c16e962f4f", + "key": "bc1b0315-d129-4d58-9013-eea4ec766761", "params": { "message": "Wait until user intervention" } }, { "commandType": "temperatureModule/deactivate", - "key": "bde12c91-d991-4d57-8d7b-172706f3aa2a", + "key": "8fd9574a-d9bf-4a7d-9b3e-c2bc99ce6e5b", "params": { "moduleId": "0b4319b0-75c7-11ea-b42f-4b64e50f43e5:temperatureModuleType" } diff --git a/protocol-designer/fixtures/protocol/8/doItAllV7MigratedToV8.json b/protocol-designer/fixtures/protocol/8/doItAllV7MigratedToV8.json index 5519ec4f502..47fe0d1f860 100644 --- a/protocol-designer/fixtures/protocol/8/doItAllV7MigratedToV8.json +++ b/protocol-designer/fixtures/protocol/8/doItAllV7MigratedToV8.json @@ -6,7 +6,7 @@ "author": "", "description": "", "created": 1689346890165, - "lastModified": 1711742514037, + "lastModified": 1714570422365, "category": null, "subcategory": null, "tags": [] @@ -15,10 +15,10 @@ "name": "opentrons/protocol-designer", "version": "8.1.0", "data": { - "_internalAppBuildDate": "Fri, 29 Mar 2024 20:00:04 GMT", + "_internalAppBuildDate": "Wed, 01 May 2024 13:32:34 GMT", "defaultValues": { "aspirate_mmFromBottom": 1, - "dispense_mmFromBottom": 0.5, + "dispense_mmFromBottom": 1, "touchTip_mmFromTop": -1, "blowout_mmFromTop": 0 }, @@ -151,7 +151,7 @@ "f9a294f1-f42b-4cae-893a-592405349d56": { "pipette": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": "100", - "tipRack": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", + "tipRack": "opentrons/opentrons_flex_96_filtertiprack_50ul/1", "changeTip": "always", "path": "single", "aspirate_wells_grouped": false, @@ -179,9 +179,8 @@ "dispense_touchTip_mmFromBottom": null, "disposalVolume_checkbox": true, "disposalVolume_volume": "100", - "blowout_z_offset": 0, "blowout_checkbox": false, - "blowout_location": "4824b094-5999-4549-9e6b-7098a9b30a8b:trashBin", + "blowout_location": "134504e1-b212-41cf-966d-2560deb5b693:trashBin", "preWetTip": false, "aspirate_airGap_checkbox": false, "aspirate_airGap_volume": "0", @@ -193,12 +192,14 @@ "dispense_delay_checkbox": false, "dispense_delay_seconds": "1", "dispense_delay_mmFromBottom": null, - "dropTip_location": "4824b094-5999-4549-9e6b-7098a9b30a8b:trashBin", + "dropTip_location": "134504e1-b212-41cf-966d-2560deb5b693:trashBin", "nozzles": null, "dispense_x_position": 0, "dispense_y_position": 0, "aspirate_x_position": 0, "aspirate_y_position": 0, + "blowout_z_offset": 0, + "blowout_flowRate": null, "id": "f9a294f1-f42b-4cae-893a-592405349d56", "stepType": "moveLiquid", "stepName": "transfer", @@ -210,9 +211,8 @@ "labware": "fcba73e7-b88e-438e-963e-f8b9a5de0983:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2", "mix_wellOrder_first": "t2b", "mix_wellOrder_second": "l2r", - "blowout_z_offset": 0, "blowout_checkbox": false, - "blowout_location": "4824b094-5999-4549-9e6b-7098a9b30a8b:trashBin", + "blowout_location": "134504e1-b212-41cf-966d-2560deb5b693:trashBin", "mix_mmFromBottom": 0.5, "pipette": "6d1e53c3-2db3-451b-ad60-3fe13781a193", "volume": "10", @@ -225,11 +225,13 @@ "dispense_delay_seconds": "1", "mix_touchTip_checkbox": false, "mix_touchTip_mmFromBottom": null, - "dropTip_location": "4824b094-5999-4549-9e6b-7098a9b30a8b:trashBin", + "dropTip_location": "134504e1-b212-41cf-966d-2560deb5b693:trashBin", "nozzles": null, - "tipRack": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", + "tipRack": "opentrons/opentrons_flex_96_filtertiprack_50ul/1", "mix_x_position": 0, "mix_y_position": 0, + "blowout_z_offset": 0, + "blowout_flowRate": null, "id": "5fdb9a12-fab4-42fd-886f-40af107b15d6", "stepType": "mix", "stepName": "mix", @@ -3761,7 +3763,7 @@ "commandSchemaId": "opentronsCommandSchemaV8", "commands": [ { - "key": "17a2f6e6-dc06-4c3a-8e97-52728d96dbd5", + "key": "a466d0dc-e276-4eca-8c03-5bf4104f7be2", "commandType": "loadPipette", "params": { "pipetteName": "p1000_single_flex", @@ -3770,7 +3772,7 @@ } }, { - "key": "23762a87-4d05-4ce1-adaf-b2e7288bfef9", + "key": "52475912-17f0-4539-9595-01e27c4a3994", "commandType": "loadPipette", "params": { "pipetteName": "p50_multi_flex", @@ -3779,7 +3781,7 @@ } }, { - "key": "74ed5557-4813-4892-a2e3-4f7710b70d1c", + "key": "9a9006cb-c81c-41ea-82ca-d7422647f7f6", "commandType": "loadModule", "params": { "model": "magneticBlockV1", @@ -3788,7 +3790,7 @@ } }, { - "key": "00beb9a8-59c7-4c99-b386-0f4214d61350", + "key": "709aa475-25dd-4c78-b9a2-c65e654b9f5d", "commandType": "loadModule", "params": { "model": "heaterShakerModuleV1", @@ -3797,7 +3799,7 @@ } }, { - "key": "347f3697-2728-4c24-9067-8e9b7d9bd1d6", + "key": "4a938cf9-7ff4-4a5e-8be8-4983f4d96e3f", "commandType": "loadModule", "params": { "model": "temperatureModuleV2", @@ -3806,7 +3808,7 @@ } }, { - "key": "89c6d0b5-71ed-4bf9-9d94-15375788b86a", + "key": "1b0bbdd3-3885-441d-9310-57809d457a09", "commandType": "loadModule", "params": { "model": "thermocyclerModuleV2", @@ -3815,7 +3817,7 @@ } }, { - "key": "07ba1a3a-9161-47ee-bf63-501e847bc84d", + "key": "328bf7a0-d0ac-4ff3-ae73-78618fd8d822", "commandType": "loadLabware", "params": { "displayName": "Opentrons 96 Flat Bottom Heater-Shaker Adapter", @@ -3829,7 +3831,7 @@ } }, { - "key": "c9aafdba-c777-4609-b99f-87405a76a7ec", + "key": "1a3bd842-7dd1-4805-be2c-99bdd24aeb84", "commandType": "loadLabware", "params": { "displayName": "Opentrons Flex 96 Filter Tip Rack 50 µL", @@ -3841,7 +3843,7 @@ } }, { - "key": "008af3b3-4557-4755-af65-4e263bcd4d52", + "key": "f4e4f3ed-5a86-41bb-a9c3-377182e26868", "commandType": "loadLabware", "params": { "displayName": "NEST 96 Well Plate 100 µL PCR Full Skirt", @@ -3855,7 +3857,7 @@ } }, { - "key": "df64c3d8-c74b-468e-b663-f88c59ed927c", + "key": "91648cab-a243-4f8e-abe0-a540eeca2e9d", "commandType": "loadLabware", "params": { "displayName": "Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap", @@ -3869,7 +3871,7 @@ } }, { - "key": "23249708-2910-493b-aa56-a05e687f13ee", + "key": "11e8b668-a20f-4080-b2ca-a782d62fd3e3", "commandType": "loadLabware", "params": { "displayName": "NEST 96 Well Plate 200 µL Flat", @@ -3884,7 +3886,7 @@ }, { "commandType": "loadLiquid", - "key": "46b4c996-8800-432b-824a-9f9fb2ae033e", + "key": "bb85f067-473e-4e12-9115-205e8dff5687", "params": { "liquidId": "1", "labwareId": "a793a135-06aa-4ed6-a1d3-c176c7810afa:opentrons/opentrons_24_aluminumblock_nest_1.5ml_snapcap/1", @@ -3893,7 +3895,7 @@ }, { "commandType": "loadLiquid", - "key": "b8e21e25-5da0-426b-a1da-8d87751e48cc", + "key": "7060bb0a-3534-49da-932e-ba8b73e46af5", "params": { "liquidId": "0", "labwareId": "fcba73e7-b88e-438e-963e-f8b9a5de0983:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2", @@ -3911,7 +3913,7 @@ }, { "commandType": "temperatureModule/setTargetTemperature", - "key": "0b60938b-1bd4-4ffb-89f6-dac42a87ac0e", + "key": "f59ece51-dd41-44db-b64b-36d232eccdf1", "params": { "moduleId": "ef44ad7f-0fd9-46d6-8bc0-c70785644cc8:temperatureModuleType", "celsius": 4 @@ -3919,7 +3921,7 @@ }, { "commandType": "heaterShaker/waitForTemperature", - "key": "7d5fd109-43cd-4dea-b0fb-2efa3f727e38", + "key": "da21219e-ef9b-4373-875c-9d5a09989aec", "params": { "moduleId": "c19dffa3-cb34-4702-bcf6-dcea786257d1:heaterShakerModuleType", "celsius": 4 @@ -3927,14 +3929,14 @@ }, { "commandType": "thermocycler/closeLid", - "key": "31bb9bbe-9c53-407a-ac73-e789b800466d", + "key": "20f3146d-9731-4efa-809e-36633bb54370", "params": { "moduleId": "627b7a27-5bb7-46de-a530-67af45652e3b:thermocyclerModuleType" } }, { "commandType": "thermocycler/setTargetLidTemperature", - "key": "0d83be22-5cec-4603-b42c-03ffb6e6d8ba", + "key": "28ee0f3a-c4b6-4e02-987d-10901017c010", "params": { "moduleId": "627b7a27-5bb7-46de-a530-67af45652e3b:thermocyclerModuleType", "celsius": 40 @@ -3942,14 +3944,14 @@ }, { "commandType": "thermocycler/waitForLidTemperature", - "key": "1ac36b4e-b0df-4d43-9cfc-a10cc64ccda3", + "key": "a8d1fb79-c73b-4ff1-9182-552e327cc60c", "params": { "moduleId": "627b7a27-5bb7-46de-a530-67af45652e3b:thermocyclerModuleType" } }, { "commandType": "thermocycler/runProfile", - "key": "0917c6de-9fd8-4afa-b496-f62ae18fa290", + "key": "f7ae03ff-0b0f-4956-8bd4-e66dbf90528f", "params": { "moduleId": "627b7a27-5bb7-46de-a530-67af45652e3b:thermocyclerModuleType", "profile": [ @@ -3961,28 +3963,28 @@ }, { "commandType": "thermocycler/deactivateBlock", - "key": "4e5e9302-fac9-438d-83c9-fabd4c65791f", + "key": "046285cc-fc6a-4191-9dca-b9b7994d4244", "params": { "moduleId": "627b7a27-5bb7-46de-a530-67af45652e3b:thermocyclerModuleType" } }, { "commandType": "thermocycler/deactivateLid", - "key": "a0fe06fa-e4cc-4de2-97a9-388a3df08111", + "key": "2decfbea-68ec-423f-a798-dc0c06a76e17", "params": { "moduleId": "627b7a27-5bb7-46de-a530-67af45652e3b:thermocyclerModuleType" } }, { "commandType": "thermocycler/openLid", - "key": "8706cf32-b7c8-41ee-901a-6e62ef7b6824", + "key": "35dc75ed-4760-42ac-9b83-d37ec2f717b0", "params": { "moduleId": "627b7a27-5bb7-46de-a530-67af45652e3b:thermocyclerModuleType" } }, { "commandType": "pickUpTip", - "key": "90d3558e-e3ef-4e11-8e18-9e1312b212b0", + "key": "97f422da-3677-412b-a859-9ca064fa8e2c", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -3991,7 +3993,7 @@ }, { "commandType": "aspirate", - "key": "c7ac4218-4698-48f4-b00d-8eeb1ffddb3a", + "key": "1c813b91-1e33-4aae-9841-20af63299a68", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4001,12 +4003,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "dispense", - "key": "604c9a1d-1ada-4159-850f-3bc9e4f802bc", + "key": "c562ed92-a5b5-4fce-8a99-f02358ab6941", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4014,14 +4016,14 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "c120780c-b4f4-4b11-a7f6-ab3b2621106f", + "key": "a7b2f8fe-b6ab-4184-8170-0647a05d7c86", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", @@ -4031,12 +4033,12 @@ }, { "commandType": "dropTipInPlace", - "key": "2b9bb184-749e-4652-a2cb-31e427ae0472", + "key": "2dee7eea-fc2a-485a-aea1-beb064e5109b", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } }, { "commandType": "pickUpTip", - "key": "24425f50-40ff-453a-9c3e-ba35f07a4b93", + "key": "35d005a3-7a97-4190-b9b0-f05d929e6c50", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4045,7 +4047,7 @@ }, { "commandType": "aspirate", - "key": "3eacc9b8-99bf-448b-b178-1638c2217d4f", + "key": "2dee8a38-087d-4f5b-85fa-c93e5a731475", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4055,12 +4057,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "dispense", - "key": "b2f71d3b-13b3-4ba5-9672-3a5ae85b402e", + "key": "6aa3c0b2-9191-4cce-9fac-908b9ecdb0ce", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4068,14 +4070,14 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "982eb315-0f07-4db4-804d-3650a7ef3371", + "key": "ef663141-ba95-4cab-83f4-a98800deb903", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", @@ -4085,12 +4087,12 @@ }, { "commandType": "dropTipInPlace", - "key": "fd1e4fcb-3f57-4e0e-9a07-f5710d713b2b", + "key": "921a5d1b-a920-4e75-b3d6-2a9385baf2a1", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } }, { "commandType": "pickUpTip", - "key": "d1aa96b8-8218-497f-92d1-9d145d65cacd", + "key": "8bb26abd-e67d-4a27-82fd-b5095e6b863a", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4099,7 +4101,7 @@ }, { "commandType": "aspirate", - "key": "49b8562e-7d04-409e-b96e-60c04d82f890", + "key": "69e87e9c-5758-4029-838a-f601d85c57c7", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4109,12 +4111,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "dispense", - "key": "16da2628-d7fa-45e9-9911-cb06a61e488e", + "key": "b8fdb45a-1bb1-4f5b-90ff-99a3f90ef378", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4122,14 +4124,14 @@ "wellName": "B1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "a7a1c2f8-6fdf-4322-a216-ca06fe064299", + "key": "3a91ac83-be4f-49e5-971f-d50995d87a5f", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", @@ -4139,12 +4141,12 @@ }, { "commandType": "dropTipInPlace", - "key": "dcfb2a3c-fec6-467e-8ea4-0655e070857c", + "key": "076167d0-7192-455c-8329-78d36e1e0bbe", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } }, { "commandType": "pickUpTip", - "key": "c54b1b14-a78e-4b3b-a7fd-df600c143996", + "key": "763fb955-8bcd-4a20-9523-ebe78894a2cc", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4153,7 +4155,7 @@ }, { "commandType": "aspirate", - "key": "1f586aaa-a2c3-4f35-98d4-514f30f8afde", + "key": "7ed1e15c-ae12-492c-8e69-9615a7128692", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4163,12 +4165,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "dispense", - "key": "8491a928-c8ae-4b73-8fd3-43e6e520ea7d", + "key": "a35f983c-9d71-41b0-b134-408254afffc9", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4176,14 +4178,14 @@ "wellName": "B1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "3ddc68fb-3f9e-4395-b234-a8f00b35cf97", + "key": "036dffc0-eb5c-4ad1-a468-2810c6d40404", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", @@ -4193,12 +4195,12 @@ }, { "commandType": "dropTipInPlace", - "key": "c1596fb8-587a-4a9c-9dd0-252dd821085c", + "key": "728b951b-ac30-42b2-8733-66047e15104d", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } }, { "commandType": "pickUpTip", - "key": "9e130b45-4d49-4588-adef-2e4055be2e09", + "key": "2f679268-9e41-4d25-a1d2-a02146993957", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4207,7 +4209,7 @@ }, { "commandType": "aspirate", - "key": "7e014576-f260-4b18-aad5-f45423adb35f", + "key": "9fc88d82-b344-4d58-bc88-21f7da6420ad", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4217,12 +4219,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "dispense", - "key": "07e28184-9669-432a-9b68-8dd692680fa5", + "key": "cd9e1f2e-8d97-4360-be45-77fef790a7ab", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4230,14 +4232,14 @@ "wellName": "C1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "4f591d38-4cc1-496b-90dc-fdcff81d3155", + "key": "09f656d5-2ca6-4496-961e-bd9e1d91b126", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", @@ -4247,12 +4249,12 @@ }, { "commandType": "dropTipInPlace", - "key": "fab6cdf0-a1c5-4643-9d0c-4fce01d88c7f", + "key": "fccb75f1-699b-4c8b-8151-dbd58d18ef06", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } }, { "commandType": "pickUpTip", - "key": "7407659a-a612-4209-967b-af9750324a07", + "key": "a3701c28-7d35-45b6-8af6-bafd6e9a4b78", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4261,7 +4263,7 @@ }, { "commandType": "aspirate", - "key": "3d307bba-026c-4a9a-8d01-ae93e8cdce1f", + "key": "4ee690e6-a74b-4417-b62a-fd3fee7d65e4", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4271,12 +4273,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "dispense", - "key": "f45088fb-f102-4edf-ad26-5d1d0ac4f215", + "key": "8eafdd0e-0d05-403d-91b2-7e5499688f93", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4284,14 +4286,14 @@ "wellName": "C1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "3b44aeec-fd56-4fcf-badf-5cdc42ed42c7", + "key": "1ca0e890-4dd7-406b-b957-ac5122beb4ed", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", @@ -4301,12 +4303,12 @@ }, { "commandType": "dropTipInPlace", - "key": "7a58db8b-f053-46b5-bd89-3a7cba9c1af1", + "key": "c4bc3f8e-96d8-48cb-ab98-9aa4f4bafda2", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } }, { "commandType": "pickUpTip", - "key": "6449dbc6-430e-468c-863d-3233689c8a63", + "key": "2f72e6b5-7349-47c6-8ed4-99b059460e7e", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4315,7 +4317,7 @@ }, { "commandType": "aspirate", - "key": "fe2b869a-8d1f-47bf-9688-2deae97b30f9", + "key": "662be64a-6a00-487c-886e-0f6c2979dd0e", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4325,12 +4327,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "dispense", - "key": "e9a20fb6-f0ba-4e25-b1e5-67dbef00f2d0", + "key": "7f81ae52-4dcd-4b71-9247-2ae073990a98", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4338,14 +4340,14 @@ "wellName": "D1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "c0c7ae2d-6b13-4ce7-b170-5a2ffb3cc066", + "key": "180c5597-e041-4f4a-a8c6-42e4f2526525", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", @@ -4355,12 +4357,12 @@ }, { "commandType": "dropTipInPlace", - "key": "eea51b62-8fd2-4c34-8929-48e26c670640", + "key": "a151f233-ffa8-487c-8058-cc58d52c4181", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } }, { "commandType": "pickUpTip", - "key": "0a59af4d-5196-4c16-b609-98c565c320da", + "key": "dcd3ad54-3401-4d65-a7c6-c6ec7f6027ec", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4369,7 +4371,7 @@ }, { "commandType": "aspirate", - "key": "cc1387fe-4e22-407f-b1f6-8e57153d24d1", + "key": "32fcd712-9792-4269-be8c-1eab474ecf4c", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4379,12 +4381,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "dispense", - "key": "fdbb2c46-7e42-4dc9-95dd-528397fe2a49", + "key": "e8b25c7f-01ad-461d-94d6-86575cc51a56", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4392,14 +4394,14 @@ "wellName": "D1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "f8000789-3db0-4edc-adaa-234a89c0a2e8", + "key": "ebf51a3b-0060-435a-afcc-873460507190", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", @@ -4409,12 +4411,12 @@ }, { "commandType": "dropTipInPlace", - "key": "4a6423a4-3fb3-41cb-a2bb-769f882da188", + "key": "e77f841b-88ec-407c-beb8-e3321040fb2a", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } }, { "commandType": "pickUpTip", - "key": "58db6a04-8af4-4580-8b3b-71d27448d36c", + "key": "e06e9602-6ec1-44e4-b6ee-192cd5597aaf", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4423,7 +4425,7 @@ }, { "commandType": "aspirate", - "key": "6c053630-6298-4bae-8b1b-b7c0fd60cd64", + "key": "2b552829-1350-47ff-8f33-e6a2705b08cc", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4433,12 +4435,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "dispense", - "key": "60bddd52-347b-4e97-af4f-227172c9e383", + "key": "69bc9bfc-b130-4594-a912-f32493df9f5c", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4446,14 +4448,14 @@ "wellName": "E1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "dcc5e7a5-ce62-40b0-94a8-19ccd9ec7783", + "key": "c8553dff-22c7-47e0-b188-fe47ba20c06f", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", @@ -4463,12 +4465,12 @@ }, { "commandType": "dropTipInPlace", - "key": "2d0d4405-02e0-44d3-9aa9-093b2bcf8693", + "key": "e6173c85-aa29-4970-a017-e1d56173d529", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } }, { "commandType": "pickUpTip", - "key": "8f943b62-e5cc-423b-962d-c9f06a3c39e6", + "key": "c4ac3ecf-35ae-444a-a4d9-b90b289d7020", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4477,7 +4479,7 @@ }, { "commandType": "aspirate", - "key": "d38287f1-db91-4479-a811-6190c472a797", + "key": "07af8116-6872-43f4-8e6a-2acfd9ae056d", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4487,12 +4489,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "dispense", - "key": "10074111-ee60-4602-8749-326cc7c978ef", + "key": "c2a1b95f-eead-476a-af6b-eaecd597c58a", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4500,14 +4502,14 @@ "wellName": "E1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "f0b5078d-30e7-4ae8-bd9c-2380a2acc248", + "key": "ae02c807-ad04-407b-a8bd-2536d326053a", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", @@ -4517,12 +4519,12 @@ }, { "commandType": "dropTipInPlace", - "key": "babbd4a6-95d0-46ef-9616-15435bf83e0c", + "key": "9ff56b91-52d2-4823-b1a7-d168b6610d39", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } }, { "commandType": "pickUpTip", - "key": "44873109-2a10-4925-a393-b3f05ac65cc8", + "key": "2ee82bb2-a652-4372-b208-79381d3a2264", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4531,7 +4533,7 @@ }, { "commandType": "aspirate", - "key": "956b196e-e6a0-4e04-9fe4-e54e8f366cd3", + "key": "fba01fbc-0c97-448e-85c0-0163f435eec9", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4541,12 +4543,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "dispense", - "key": "d9fe1d4f-558e-48e9-9c4f-3349a513da68", + "key": "899aee37-aa0f-499b-8d81-87e50da36e24", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4554,14 +4556,14 @@ "wellName": "F1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "3410b8d0-d4be-4009-be92-13d7165fa45d", + "key": "d90d5984-3d21-464c-b92a-81a00180e27a", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", @@ -4571,12 +4573,12 @@ }, { "commandType": "dropTipInPlace", - "key": "b610b324-aa96-44ed-95d0-fa7b6b2771f7", + "key": "4b7837b9-6c57-4349-9411-f5cd659fdf44", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } }, { "commandType": "pickUpTip", - "key": "37fe97fb-40d5-449a-ab57-995eb34db25b", + "key": "073269b2-c1ef-4568-be8a-e700e01c1fb0", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4585,7 +4587,7 @@ }, { "commandType": "aspirate", - "key": "f8fe5dca-1294-4f9a-8b05-7b818317070a", + "key": "7f2b602e-f8f3-481f-9bcf-a149126f6b55", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4595,12 +4597,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "dispense", - "key": "9ae4ac38-6188-4e0a-82b1-c8682052eab7", + "key": "0fe0f127-2b1c-4d2d-ab09-d860f3cceead", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4608,14 +4610,14 @@ "wellName": "F1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "5a3d6103-e920-419f-8541-6f42aead55b4", + "key": "e1977b77-4bb4-4065-b4df-71a45adc0456", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", @@ -4625,12 +4627,12 @@ }, { "commandType": "dropTipInPlace", - "key": "ae7fa272-1052-4b9b-9141-832de7f191ae", + "key": "bfe36534-d079-4187-a2a5-9438bcd9c33f", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } }, { "commandType": "pickUpTip", - "key": "001e1eff-7e3a-4762-889b-81bbdd95624e", + "key": "07a11b3e-ed6f-4ba3-8c0a-470b956cf7e0", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4639,7 +4641,7 @@ }, { "commandType": "aspirate", - "key": "4c857bd6-9ee5-4abc-b8f1-93f263421d4f", + "key": "e5b0fda2-844a-4edb-b91b-3c41936dac98", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4649,12 +4651,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "dispense", - "key": "d54ee4e1-019a-4043-a9d6-73f2728ade40", + "key": "571ad2e1-63a6-40d6-8a3b-f1750059ae7f", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4662,14 +4664,14 @@ "wellName": "G1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "b3d1a836-8198-4543-9c69-5af4340f5e7b", + "key": "0b034b3e-45c4-4cb9-b820-357f3e230e55", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", @@ -4679,12 +4681,12 @@ }, { "commandType": "dropTipInPlace", - "key": "d09a4c10-5d65-46b2-aa72-04ebd1e69616", + "key": "2da8c88c-d811-4b24-a8c3-483fbb746ecf", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } }, { "commandType": "pickUpTip", - "key": "a18317f2-d1e8-4960-8294-d041900be78c", + "key": "751d9a11-3483-4b6f-bb41-7599943010ad", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4693,7 +4695,7 @@ }, { "commandType": "aspirate", - "key": "7b5f0098-2f53-4e57-b60a-46c06f4fe167", + "key": "69b99917-3f64-40ea-b8b6-8c151a50138b", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4703,12 +4705,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "dispense", - "key": "e6497c4f-50da-481e-b76d-a6787df6a779", + "key": "7cf6c2ab-0fae-4ecb-8170-f88aaa06a661", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4716,14 +4718,14 @@ "wellName": "G1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "7c357bd8-9b73-43d0-a143-57d9b24d651f", + "key": "d6841291-2f66-444c-9075-479264b99da2", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", @@ -4733,12 +4735,12 @@ }, { "commandType": "dropTipInPlace", - "key": "5ea9d3e3-5c64-4610-bbfc-b71d7e4d3282", + "key": "a31c0031-274d-4b0d-9a1e-5798c30ec56a", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } }, { "commandType": "pickUpTip", - "key": "17f52737-8fa4-45df-95e1-e95011c308fd", + "key": "a79d29d3-2c41-4c92-8c6a-d326490796c1", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4747,7 +4749,7 @@ }, { "commandType": "aspirate", - "key": "43f318b4-d316-462b-9d38-d4969cac5494", + "key": "c1d0c16c-ac57-458b-9684-28a980d2bfb8", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4757,12 +4759,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "dispense", - "key": "ed84c3b2-b095-49bc-939b-fd1f5faa6ddd", + "key": "b3bfc4e3-cc87-4d0a-bf93-e011e94f1faa", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4770,14 +4772,14 @@ "wellName": "H1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "bdde31de-c35d-403a-bc01-d249c21100dd", + "key": "562b921d-47ef-410f-a6e9-89ca3de47781", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", @@ -4787,12 +4789,12 @@ }, { "commandType": "dropTipInPlace", - "key": "2d5caff3-718e-4835-90c1-3a0d2ec57a20", + "key": "0a571744-aab1-4e5f-8714-4ef214eed2b4", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } }, { "commandType": "pickUpTip", - "key": "a9e33581-f053-47cb-9bc4-069dca4fbc1c", + "key": "76f26d7f-424a-47d7-b58b-25da0153e99e", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4801,7 +4803,7 @@ }, { "commandType": "aspirate", - "key": "5b34a48a-fdf2-4ad1-8c14-3da9ffb680ed", + "key": "2ee21344-b3c9-4a1c-8d16-ba87685c941d", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4811,12 +4813,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "dispense", - "key": "13cfa89d-7337-4358-86d2-0da34380835d", + "key": "0aa240d7-4f11-4e27-b267-b2293756ccd9", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4824,14 +4826,14 @@ "wellName": "H1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 6 + "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "ec94b555-dba0-4757-be27-7b8634c55a9a", + "key": "7ce94c87-441f-4b94-b130-2ac389df6173", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", @@ -4841,12 +4843,12 @@ }, { "commandType": "dropTipInPlace", - "key": "efba76a3-5a32-4f02-9dfc-2f1e5ff3e9b6", + "key": "3d97c296-3db4-4aeb-a90a-d606b403b06f", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } }, { "commandType": "pickUpTip", - "key": "844f8618-5db6-48ba-b0af-ffc12e84eea7", + "key": "8f82c107-45a2-4a38-84fc-66f0271d2801", "params": { "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4855,7 +4857,7 @@ }, { "commandType": "configureForVolume", - "key": "5d899711-013e-460b-845b-9a8ef207dc24", + "key": "756cc4d4-1166-43e6-973e-e36da881b3b8", "params": { "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193", "volume": 10 @@ -4863,7 +4865,7 @@ }, { "commandType": "aspirate", - "key": "71923e56-ac8f-486c-9509-c809a994e006", + "key": "11e401a4-f3f9-4140-8440-b9720b25e64b", "params": { "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193", "volume": 10, @@ -4873,12 +4875,12 @@ "origin": "bottom", "offset": { "z": 0.5, "x": 0, "y": 0 } }, - "flowRate": 8 + "flowRate": 35 } }, { "commandType": "dispense", - "key": "abde93a4-98e5-428c-9dd9-2a65dc3d99bf", + "key": "d203a431-0e58-4eae-a58a-1867345d2097", "params": { "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193", "volume": 10, @@ -4888,12 +4890,12 @@ "origin": "bottom", "offset": { "z": 0.5, "x": 0, "y": 0 } }, - "flowRate": 8 + "flowRate": 57 } }, { "commandType": "aspirate", - "key": "f9a0576f-5764-478e-bf16-03ef8ab46d3b", + "key": "47cd47b9-0e5e-4cfb-8a34-04e38972042f", "params": { "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193", "volume": 10, @@ -4903,12 +4905,12 @@ "origin": "bottom", "offset": { "z": 0.5, "x": 0, "y": 0 } }, - "flowRate": 8 + "flowRate": 35 } }, { "commandType": "dispense", - "key": "e1e8644f-f0d0-4946-b599-55d62174b5af", + "key": "8c82d2df-c0b3-4e83-84b7-c49c5a679d7a", "params": { "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193", "volume": 10, @@ -4918,12 +4920,12 @@ "origin": "bottom", "offset": { "z": 0.5, "x": 0, "y": 0 } }, - "flowRate": 8 + "flowRate": 57 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "9bb9217e-3c87-4b11-81f4-01aeb6d12bcd", + "key": "87891819-4db8-485f-ac1c-2cb8dfa8da58", "params": { "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193", "addressableAreaName": "movableTrashA3", @@ -4933,12 +4935,12 @@ }, { "commandType": "dropTipInPlace", - "key": "dd0506d4-cd19-4fa3-85db-64aef25d8f75", + "key": "c8b87235-132f-4c2b-8d4e-b09292e6bbeb", "params": { "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193" } }, { "commandType": "moveLabware", - "key": "bd579612-fa2a-4808-ade0-8e38b9d8b7da", + "key": "70be0944-8068-4d60-aa0f-9d157c6419a5", "params": { "labwareId": "fcba73e7-b88e-438e-963e-f8b9a5de0983:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2", "strategy": "usingGripper", @@ -4947,12 +4949,12 @@ }, { "commandType": "waitForDuration", - "key": "da8a328a-2870-4259-b3be-89d3255154fb", + "key": "fef747ed-386a-4b20-9cf1-e37c46181425", "params": { "seconds": 60, "message": "" } }, { "commandType": "moveLabware", - "key": "64ac3bcc-4ab8-4d15-9b42-d2462686153d", + "key": "e837119a-5b27-46f1-b451-212a7df67b07", "params": { "labwareId": "fcba73e7-b88e-438e-963e-f8b9a5de0983:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2", "strategy": "usingGripper", @@ -4961,21 +4963,21 @@ }, { "commandType": "heaterShaker/closeLabwareLatch", - "key": "cd0e65dc-cd6c-4d0f-b05f-3d8a979d7d09", + "key": "8b4b0719-bc42-4ed4-8ce0-a7a7cedf66ea", "params": { "moduleId": "c19dffa3-cb34-4702-bcf6-dcea786257d1:heaterShakerModuleType" } }, { "commandType": "heaterShaker/deactivateHeater", - "key": "c980a10c-a99c-4583-831b-8f09f89822fd", + "key": "3b7b0570-3a7a-4e33-9bad-b059fe89c1a1", "params": { "moduleId": "c19dffa3-cb34-4702-bcf6-dcea786257d1:heaterShakerModuleType" } }, { "commandType": "heaterShaker/setAndWaitForShakeSpeed", - "key": "15a3aeed-9bd0-49d6-8a6e-43f226e7acfe", + "key": "2f7bcf2d-638d-4dcc-8024-56d5ecaf2295", "params": { "moduleId": "c19dffa3-cb34-4702-bcf6-dcea786257d1:heaterShakerModuleType", "rpm": 500 @@ -4983,28 +4985,28 @@ }, { "commandType": "heaterShaker/deactivateHeater", - "key": "001d2bdd-b8a2-4285-8aa3-9d9318566b47", + "key": "8949fdba-7c3e-4f80-a875-196c32f509a6", "params": { "moduleId": "c19dffa3-cb34-4702-bcf6-dcea786257d1:heaterShakerModuleType" } }, { "commandType": "heaterShaker/deactivateShaker", - "key": "609e5b71-9dda-47d7-a7c4-0da3802e7e99", + "key": "9fed3869-0f75-4283-b074-9b6d9024f265", "params": { "moduleId": "c19dffa3-cb34-4702-bcf6-dcea786257d1:heaterShakerModuleType" } }, { "commandType": "heaterShaker/openLabwareLatch", - "key": "bb80d557-573b-4b09-a0b8-5d73ea22e4a4", + "key": "9d2c8737-d1e2-4536-8c62-438680f796d2", "params": { "moduleId": "c19dffa3-cb34-4702-bcf6-dcea786257d1:heaterShakerModuleType" } }, { "commandType": "moveLabware", - "key": "a37c38e0-7abe-433f-ab9d-adf0774565f6", + "key": "8135e5e6-0d7a-4671-948a-4820a609c7ff", "params": { "labwareId": "a793a135-06aa-4ed6-a1d3-c176c7810afa:opentrons/opentrons_24_aluminumblock_nest_1.5ml_snapcap/1", "strategy": "manualMoveWithPause", @@ -5013,14 +5015,14 @@ }, { "commandType": "temperatureModule/deactivate", - "key": "1558d15f-e4b6-48bb-8c9c-c3ff69812504", + "key": "b71aa9a8-2433-4896-936d-ab813c8018df", "params": { "moduleId": "ef44ad7f-0fd9-46d6-8bc0-c70785644cc8:temperatureModuleType" } }, { "commandType": "moveLabware", - "key": "d805d58b-f6e7-406d-8262-5bf3d03448b6", + "key": "e896fc7d-b93e-4507-84bf-5af3d69ce722", "params": { "labwareId": "239ceac8-23ec-4900-810a-70aeef880273:opentrons/nest_96_wellplate_200ul_flat/2", "strategy": "manualMoveWithPause", diff --git a/protocol-designer/fixtures/protocol/8/doItAllV8.json b/protocol-designer/fixtures/protocol/8/doItAllV8.json index 2a0e6bcde5d..61f1e788852 100644 --- a/protocol-designer/fixtures/protocol/8/doItAllV8.json +++ b/protocol-designer/fixtures/protocol/8/doItAllV8.json @@ -6,7 +6,7 @@ "author": "", "description": "", "created": 1701659107408, - "lastModified": 1711742533084, + "lastModified": 1714570438503, "category": null, "subcategory": null, "tags": [] @@ -15,10 +15,10 @@ "name": "opentrons/protocol-designer", "version": "8.1.0", "data": { - "_internalAppBuildDate": "Fri, 29 Mar 2024 20:00:04 GMT", + "_internalAppBuildDate": "Wed, 01 May 2024 13:32:34 GMT", "defaultValues": { "aspirate_mmFromBottom": 1, - "dispense_mmFromBottom": 0.5, + "dispense_mmFromBottom": 1, "touchTip_mmFromTop": -1, "blowout_mmFromTop": 0 }, @@ -111,7 +111,7 @@ "d2f74144-a7bf-4ba2-aaab-30d70b2b62c7": { "pipette": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "volume": "100", - "tipRack": "f2d371ea-5146-4c89-8200-9c056a7f321a:opentrons/opentrons_flex_96_tiprack_1000ul/1", + "tipRack": "opentrons/opentrons_flex_96_tiprack_1000ul/1", "changeTip": "always", "path": "single", "aspirate_wells_grouped": false, @@ -159,6 +159,7 @@ "aspirate_x_position": 0, "aspirate_y_position": 0, "blowout_z_offset": 0, + "blowout_flowRate": null, "id": "d2f74144-a7bf-4ba2-aaab-30d70b2b62c7", "stepType": "moveLiquid", "stepName": "transfer", @@ -3426,7 +3427,7 @@ "commandSchemaId": "opentronsCommandSchemaV8", "commands": [ { - "key": "f8a4cabe-7cb9-4e38-b937-6655680e2a31", + "key": "a1b95079-5b17-428d-b40c-a8236a9890c5", "commandType": "loadPipette", "params": { "pipetteName": "p1000_single_flex", @@ -3435,7 +3436,7 @@ } }, { - "key": "cd2e6185-8d57-4881-9b0c-ebcbd2468c55", + "key": "6f1e3ad3-8f03-4583-8031-be6be2fcd903", "commandType": "loadModule", "params": { "model": "heaterShakerModuleV1", @@ -3444,7 +3445,7 @@ } }, { - "key": "b2d44cd2-73db-45b3-ab22-e9e765beed75", + "key": "4997a543-7788-434f-8eae-1c4aa3a2a805", "commandType": "loadModule", "params": { "model": "thermocyclerModuleV2", @@ -3453,7 +3454,7 @@ } }, { - "key": "bbd3ee7e-35b8-4168-9df5-13b871c6dfba", + "key": "8bfb6d48-4d08-4ea0-8ce7-f8efe90e202c", "commandType": "loadLabware", "params": { "displayName": "Opentrons 96 PCR Heater-Shaker Adapter", @@ -3467,7 +3468,7 @@ } }, { - "key": "198896f6-4d0e-49ee-b060-bc9d17fbb9bc", + "key": "988395e3-9b85-4bb0-89a4-3afc1d7330fd", "commandType": "loadLabware", "params": { "displayName": "Opentrons Flex 96 Tip Rack 1000 µL", @@ -3479,7 +3480,7 @@ } }, { - "key": "880af66e-2905-4102-b655-0351b30252b1", + "key": "0d60425e-5a6f-4205-ac59-d38a080f2e92", "commandType": "loadLabware", "params": { "displayName": "Opentrons Tough 96 Well Plate 200 µL PCR Full Skirt", @@ -3493,7 +3494,7 @@ } }, { - "key": "478e31cc-12f4-4a30-9cd4-03181a538513", + "key": "eba272e9-3eed-46bb-91aa-d1aee8da58da", "commandType": "loadLabware", "params": { "displayName": "Axygen 1 Well Reservoir 90 mL", @@ -3506,7 +3507,7 @@ }, { "commandType": "loadLiquid", - "key": "56bffeaa-ee2b-4cb8-91dc-a9e21e8f1655", + "key": "45d432f8-581b-4272-9813-e73b9168a0ad", "params": { "liquidId": "1", "labwareId": "54370838-4fca-4a14-b88a-7840e4903649:opentrons/opentrons_96_wellplate_200ul_pcr_full_skirt/2", @@ -3524,7 +3525,7 @@ }, { "commandType": "loadLiquid", - "key": "e95ef8f9-fef7-4dfe-b5db-86a5dff7e5b5", + "key": "7ec93f2a-3d22-4d30-b37a-e9f0d41a1847", "params": { "liquidId": "0", "labwareId": "8bacda22-9e05-45e8-bef4-cc04414a204f:opentrons/axygen_1_reservoir_90ml/1", @@ -3533,14 +3534,14 @@ }, { "commandType": "thermocycler/openLid", - "key": "63d31323-1217-4a56-9392-c1c28dc703d7", + "key": "ba1731c6-2906-4987-b948-ea1931ad3e64", "params": { "moduleId": "fd6da9f1-d63b-414b-929e-c646b64790e9:thermocyclerModuleType" } }, { "commandType": "moveLabware", - "key": "716ec050-c597-490d-b261-20ac8e3b4c2f", + "key": "134cdae8-8ba1-45e4-98d7-cb931358eb01", "params": { "labwareId": "8bacda22-9e05-45e8-bef4-cc04414a204f:opentrons/axygen_1_reservoir_90ml/1", "strategy": "usingGripper", @@ -3549,7 +3550,7 @@ }, { "commandType": "pickUpTip", - "key": "635b128e-5cdc-4bdc-9975-c04a49fb7670", + "key": "6a5f30cc-8bea-4899-b058-7bf2095efe86", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "labwareId": "f2d371ea-5146-4c89-8200-9c056a7f321a:opentrons/opentrons_flex_96_tiprack_1000ul/1", @@ -3558,7 +3559,7 @@ }, { "commandType": "aspirate", - "key": "1a26a0e0-11c2-4940-b32d-8c747e6969a7", + "key": "71fc15e9-ad19-4c77-a32f-abba4ea5e6f9", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "volume": 100, @@ -3568,12 +3569,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 160 + "flowRate": 716 } }, { "commandType": "dispense", - "key": "17f82c54-3e03-46f4-9c65-666aacc5bab3", + "key": "a94a08b1-ed23-4c91-a853-27192da2aa70", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "volume": 100, @@ -3581,14 +3582,14 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 160 + "flowRate": 716 } }, { "commandType": "moveToAddressableArea", - "key": "d38dc37e-e466-47c9-a7bc-85322487af8c", + "key": "9f8c952b-88e2-4a6d-b6a2-e943f9b032e0", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "addressableAreaName": "1ChannelWasteChute", @@ -3597,12 +3598,12 @@ }, { "commandType": "dropTipInPlace", - "key": "69952335-9a0e-4b69-a903-00454f162e8f", + "key": "734f7c4e-be2c-4a45-ae26-d81fb6b58729", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc" } }, { "commandType": "pickUpTip", - "key": "2a6d6805-bb22-42c6-9d38-321bdbd9f941", + "key": "e3f54bb0-ef58-4e56-ad44-1dc944d2ebd8", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "labwareId": "f2d371ea-5146-4c89-8200-9c056a7f321a:opentrons/opentrons_flex_96_tiprack_1000ul/1", @@ -3611,7 +3612,7 @@ }, { "commandType": "aspirate", - "key": "087e94b5-a8f7-4637-a830-eb99e2d3a631", + "key": "d5dee037-06a2-4f63-a5dd-08f285db802f", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "volume": 100, @@ -3621,12 +3622,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 160 + "flowRate": 716 } }, { "commandType": "dispense", - "key": "6edf7c6f-858c-4170-9b69-9f230144ba8a", + "key": "db77cb48-9d63-4eb9-bac9-82c7137c7940", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "volume": 100, @@ -3634,14 +3635,14 @@ "wellName": "B1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 160 + "flowRate": 716 } }, { "commandType": "moveToAddressableArea", - "key": "129a19fb-6a84-4196-a712-7400142cfff2", + "key": "c4a205b9-6a31-4993-a7dd-de84e3c40fab", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "addressableAreaName": "1ChannelWasteChute", @@ -3650,12 +3651,12 @@ }, { "commandType": "dropTipInPlace", - "key": "46e0edd9-a8eb-4dc4-840d-496ce6ecb732", + "key": "c1a58bc4-c922-4989-8259-3a011cb6548e", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc" } }, { "commandType": "pickUpTip", - "key": "2c31e97a-5821-4fd9-b171-d29ac18cda36", + "key": "4660a8b7-c24f-4cbd-b5f7-0fff091af818", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "labwareId": "f2d371ea-5146-4c89-8200-9c056a7f321a:opentrons/opentrons_flex_96_tiprack_1000ul/1", @@ -3664,7 +3665,7 @@ }, { "commandType": "aspirate", - "key": "c5d54202-b261-497f-aa71-3bbdb73f2441", + "key": "9ac1cb1d-2876-4816-87bc-bcbeb3d0cc45", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "volume": 100, @@ -3674,12 +3675,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 160 + "flowRate": 716 } }, { "commandType": "dispense", - "key": "df57bdd7-104c-4923-a561-002043500c74", + "key": "1e8856de-95c7-483f-bf9a-a8a08dbd51b5", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "volume": 100, @@ -3687,14 +3688,14 @@ "wellName": "C1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 160 + "flowRate": 716 } }, { "commandType": "moveToAddressableArea", - "key": "eddd8f7b-ccd6-4919-885d-bf20bbbc675f", + "key": "df45d90b-b122-4a73-8166-7c36cb4b1739", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "addressableAreaName": "1ChannelWasteChute", @@ -3703,12 +3704,12 @@ }, { "commandType": "dropTipInPlace", - "key": "2f5e18c4-1436-47f1-9010-975fe41ca901", + "key": "893249ff-853b-4294-bd2c-12da0e5cb8af", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc" } }, { "commandType": "pickUpTip", - "key": "c4508229-340b-42af-850c-f8d4d10caeae", + "key": "2e4913f4-1f2e-4039-964b-ca6f8905e551", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "labwareId": "f2d371ea-5146-4c89-8200-9c056a7f321a:opentrons/opentrons_flex_96_tiprack_1000ul/1", @@ -3717,7 +3718,7 @@ }, { "commandType": "aspirate", - "key": "7b548807-dd81-479e-a00f-b4cd9d2080ff", + "key": "bd2ac396-b44d-41a8-b050-ff8ab4a25575", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "volume": 100, @@ -3727,12 +3728,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 160 + "flowRate": 716 } }, { "commandType": "dispense", - "key": "8d8053f6-f155-416c-986c-1893f87d979f", + "key": "df68ab20-61c0-4077-bf0e-b1ef2997251a", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "volume": 100, @@ -3740,14 +3741,14 @@ "wellName": "D1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 160 + "flowRate": 716 } }, { "commandType": "moveToAddressableArea", - "key": "92fa7df4-7cd5-42fd-8405-7baf417b46e3", + "key": "4b7f1a58-2bf5-45e8-a312-e165130f208c", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "addressableAreaName": "1ChannelWasteChute", @@ -3756,12 +3757,12 @@ }, { "commandType": "dropTipInPlace", - "key": "b2cc5f6e-dc14-4a5e-8f54-1fbcf779e850", + "key": "2fc06e3a-f20d-47b9-ac7f-0a062b45beeb", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc" } }, { "commandType": "pickUpTip", - "key": "149f4bc1-ecb0-49c8-bf2a-9e1dc7d241dc", + "key": "9b4955da-0d09-40da-83b2-6c398dcf5e6e", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "labwareId": "f2d371ea-5146-4c89-8200-9c056a7f321a:opentrons/opentrons_flex_96_tiprack_1000ul/1", @@ -3770,7 +3771,7 @@ }, { "commandType": "aspirate", - "key": "43ee041e-de88-4f88-8d40-700334aaf355", + "key": "05a4a082-6381-4107-bb26-0e64351d3263", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "volume": 100, @@ -3780,12 +3781,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 160 + "flowRate": 716 } }, { "commandType": "dispense", - "key": "779c450d-0d43-4b71-aa73-5f29ed51f5dd", + "key": "a494e205-1cf5-4718-b5f0-43fe74c962bc", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "volume": 100, @@ -3793,14 +3794,14 @@ "wellName": "E1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 160 + "flowRate": 716 } }, { "commandType": "moveToAddressableArea", - "key": "b2be4778-5e00-4bc1-8431-cdecb7ad74ad", + "key": "e4cf4c42-d1c3-40e7-9848-3e02e01250a8", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "addressableAreaName": "1ChannelWasteChute", @@ -3809,12 +3810,12 @@ }, { "commandType": "dropTipInPlace", - "key": "4fa0e93d-1f79-4af5-9bbf-c0e41f131053", + "key": "397d6c15-97ae-4ab5-a2dc-e0fe75562d17", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc" } }, { "commandType": "pickUpTip", - "key": "77a07fa4-8e68-49c2-aad8-74f04328a34b", + "key": "86178307-33f6-4902-9207-51fc704d579c", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "labwareId": "f2d371ea-5146-4c89-8200-9c056a7f321a:opentrons/opentrons_flex_96_tiprack_1000ul/1", @@ -3823,7 +3824,7 @@ }, { "commandType": "aspirate", - "key": "06c28a5b-53c6-4aa5-89e0-30b509d2c68f", + "key": "f2964ad3-9dac-4566-b636-afb59de61116", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "volume": 100, @@ -3833,12 +3834,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 160 + "flowRate": 716 } }, { "commandType": "dispense", - "key": "0caa3ced-9327-48aa-b59f-07ea65a81702", + "key": "68c9104b-3796-4ca1-9bc5-22afec8024d9", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "volume": 100, @@ -3846,14 +3847,14 @@ "wellName": "F1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 160 + "flowRate": 716 } }, { "commandType": "moveToAddressableArea", - "key": "592051e7-385f-49eb-aeb2-aca173c7e8d4", + "key": "9a10a801-1aaa-4238-89a9-c256f09deea0", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "addressableAreaName": "1ChannelWasteChute", @@ -3862,12 +3863,12 @@ }, { "commandType": "dropTipInPlace", - "key": "10c97227-329e-453d-bc1c-16b929cc7ad5", + "key": "73d1b9c9-4c1f-40a2-8932-7f0110da78dc", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc" } }, { "commandType": "pickUpTip", - "key": "a85a3cb6-68e8-43d4-8c87-218bca8fe3ae", + "key": "5818e249-0b61-4f76-af80-c835a4ad0033", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "labwareId": "f2d371ea-5146-4c89-8200-9c056a7f321a:opentrons/opentrons_flex_96_tiprack_1000ul/1", @@ -3876,7 +3877,7 @@ }, { "commandType": "aspirate", - "key": "8804e9b7-b0e6-4814-bf38-48a5b05fb106", + "key": "38df8344-789d-4490-bd8a-cbe9121b2692", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "volume": 100, @@ -3886,12 +3887,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 160 + "flowRate": 716 } }, { "commandType": "dispense", - "key": "5cf8eaf7-c60d-41e2-bb90-c10b3dcb092f", + "key": "13593038-b554-447e-9963-0f3666ccd11a", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "volume": 100, @@ -3899,14 +3900,14 @@ "wellName": "G1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 160 + "flowRate": 716 } }, { "commandType": "moveToAddressableArea", - "key": "f3e72ab1-d7ea-4857-aa42-8f25b2ec5d1b", + "key": "361985e0-7e23-4651-b0ed-5277cb5f1bec", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "addressableAreaName": "1ChannelWasteChute", @@ -3915,12 +3916,12 @@ }, { "commandType": "dropTipInPlace", - "key": "2a0395ec-7363-407b-a391-e8e361d5098b", + "key": "0d1c0aa2-d5f6-45d9-9341-bc623c07f366", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc" } }, { "commandType": "pickUpTip", - "key": "3246289c-9e03-43d4-8451-e6736a8a709d", + "key": "ef384b08-03fd-4ec1-8ea9-f7741ac9050e", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "labwareId": "f2d371ea-5146-4c89-8200-9c056a7f321a:opentrons/opentrons_flex_96_tiprack_1000ul/1", @@ -3929,7 +3930,7 @@ }, { "commandType": "aspirate", - "key": "470b2170-edec-412a-beeb-56de7f85c0ea", + "key": "29bcc74a-cbba-4d19-9150-889378a34530", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "volume": 100, @@ -3939,12 +3940,12 @@ "origin": "bottom", "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 160 + "flowRate": 716 } }, { "commandType": "dispense", - "key": "dec80858-857c-4ca9-89d1-235affcdfbc8", + "key": "e1f51c21-1522-4538-af60-b97dc37d7b9a", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "volume": 100, @@ -3952,14 +3953,14 @@ "wellName": "H1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { "z": 1, "x": 0, "y": 0 } }, - "flowRate": 160 + "flowRate": 716 } }, { "commandType": "moveToAddressableArea", - "key": "998c55f5-86d6-4ba3-ac30-33d818357753", + "key": "93516cec-406e-41e8-8c4c-9b2b145509f7", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc", "addressableAreaName": "1ChannelWasteChute", @@ -3968,19 +3969,19 @@ }, { "commandType": "dropTipInPlace", - "key": "47eadfc8-8244-4509-9462-2fa624b8488a", + "key": "d9a0a1d2-f813-488e-a28a-daae69cbc072", "params": { "pipetteId": "9fcd50d9-92b2-45ac-acf1-e2cf773feffc" } }, { "commandType": "thermocycler/closeLid", - "key": "15e90989-96e1-4e86-9381-d56db11b7659", + "key": "6c34d1f1-bfeb-46d9-9669-c9b71732b6ab", "params": { "moduleId": "fd6da9f1-d63b-414b-929e-c646b64790e9:thermocyclerModuleType" } }, { "commandType": "thermocycler/setTargetBlockTemperature", - "key": "0dc52334-283f-458d-91a7-3b19c722a8f6", + "key": "5ec65b6a-2b1c-4f8c-961f-c6e0ee700b49", "params": { "moduleId": "fd6da9f1-d63b-414b-929e-c646b64790e9:thermocyclerModuleType", "celsius": 40 @@ -3988,47 +3989,47 @@ }, { "commandType": "thermocycler/waitForBlockTemperature", - "key": "78800364-855d-467f-8f52-8838892375d2", + "key": "9f90e933-131f-44eb-ab12-efb152c9cb83", "params": { "moduleId": "fd6da9f1-d63b-414b-929e-c646b64790e9:thermocyclerModuleType" } }, { "commandType": "waitForDuration", - "key": "264eed35-aa11-454f-83e1-3771ca54b87a", + "key": "f580c50f-08bb-42c4-b4a2-2764ed2fc090", "params": { "seconds": 60, "message": "" } }, { "commandType": "thermocycler/openLid", - "key": "80009058-c8ad-4da4-80da-9167e79188aa", + "key": "f739bfc8-f438-4fa2-8d57-dc839ac29f24", "params": { "moduleId": "fd6da9f1-d63b-414b-929e-c646b64790e9:thermocyclerModuleType" } }, { "commandType": "thermocycler/deactivateBlock", - "key": "e8109b8f-f380-44b5-965a-40867be7765b", + "key": "4561d98c-b565-48db-a7af-6bcd31520340", "params": { "moduleId": "fd6da9f1-d63b-414b-929e-c646b64790e9:thermocyclerModuleType" } }, { "commandType": "heaterShaker/deactivateHeater", - "key": "389a88e8-7267-4cd8-bd5b-22e86d06150d", + "key": "79dd17bf-f86a-4fe9-990a-e4e567798c87", "params": { "moduleId": "23347241-80bb-4a7e-9c91-5d9727a9e483:heaterShakerModuleType" } }, { "commandType": "heaterShaker/openLabwareLatch", - "key": "de12dc4b-89b8-42be-801d-02b70e3b04ff", + "key": "995a2630-7a9c-4b70-aef8-ddccb7ce26ce", "params": { "moduleId": "23347241-80bb-4a7e-9c91-5d9727a9e483:heaterShakerModuleType" } }, { "commandType": "moveLabware", - "key": "8822ab1b-89a9-4b0c-abac-1e3abb792d63", + "key": "9d1035a4-617f-4fcc-a7a3-1b7a8c52b4c6", "params": { "labwareId": "54370838-4fca-4a14-b88a-7840e4903649:opentrons/opentrons_96_wellplate_200ul_pcr_full_skirt/2", "strategy": "usingGripper", @@ -4039,21 +4040,21 @@ }, { "commandType": "heaterShaker/closeLabwareLatch", - "key": "91e9ed0e-4d2e-4eb9-b49b-0e30e5b5ea9d", + "key": "a244eacc-4cbc-48af-b54a-6c08cd534a51", "params": { "moduleId": "23347241-80bb-4a7e-9c91-5d9727a9e483:heaterShakerModuleType" } }, { "commandType": "heaterShaker/deactivateHeater", - "key": "1c03bbae-0989-4d1a-87c9-ee73003298ab", + "key": "a6970f26-4800-4949-8592-d977df547d8b", "params": { "moduleId": "23347241-80bb-4a7e-9c91-5d9727a9e483:heaterShakerModuleType" } }, { "commandType": "heaterShaker/setAndWaitForShakeSpeed", - "key": "af3f5cbc-801c-425f-a4c7-04c5bac0826c", + "key": "ef808dac-1e14-47a1-843d-ce4ce63bdfce", "params": { "moduleId": "23347241-80bb-4a7e-9c91-5d9727a9e483:heaterShakerModuleType", "rpm": 200 @@ -4061,40 +4062,40 @@ }, { "commandType": "waitForDuration", - "key": "af1c659a-fcbb-46aa-9c1b-6f233dee281e", + "key": "5b47f11e-0755-47d2-b844-f1363e28a54e", "params": { "seconds": 60 } }, { "commandType": "heaterShaker/deactivateShaker", - "key": "ca120664-8293-4e0f-b8fd-2feb4c75cbf9", + "key": "614ec8d0-8abf-4aa4-b771-23ff2bde2881", "params": { "moduleId": "23347241-80bb-4a7e-9c91-5d9727a9e483:heaterShakerModuleType" } }, { "commandType": "heaterShaker/deactivateHeater", - "key": "abb2cb21-1848-4b51-a769-0bb74b8b0aa0", + "key": "dbbe307e-d361-4cb9-afe7-afeab944bfce", "params": { "moduleId": "23347241-80bb-4a7e-9c91-5d9727a9e483:heaterShakerModuleType" } }, { "commandType": "heaterShaker/deactivateHeater", - "key": "bd384e07-ddc3-430b-aa2d-04c9b874b130", + "key": "62f98610-cbff-4acb-ba36-a3fbb9527ba9", "params": { "moduleId": "23347241-80bb-4a7e-9c91-5d9727a9e483:heaterShakerModuleType" } }, { "commandType": "heaterShaker/openLabwareLatch", - "key": "25b0e4d1-ebd9-419f-ba55-691724c6ab66", + "key": "81cfeab1-175f-4501-8732-1ea1bc9b528b", "params": { "moduleId": "23347241-80bb-4a7e-9c91-5d9727a9e483:heaterShakerModuleType" } }, { "commandType": "moveLabware", - "key": "26c1f526-457b-46c2-9fe6-30fd595feabc", + "key": "279df4d0-2c87-4f01-b016-5c42d5edce96", "params": { "labwareId": "54370838-4fca-4a14-b88a-7840e4903649:opentrons/opentrons_96_wellplate_200ul_pcr_full_skirt/2", "strategy": "usingGripper", @@ -4103,7 +4104,7 @@ }, { "commandType": "moveLabware", - "key": "b64778b0-86e3-495a-809d-90a4a636c3ff", + "key": "f88f41dc-ddf9-4242-9ba4-21bd728ca25f", "params": { "labwareId": "f2d371ea-5146-4c89-8200-9c056a7f321a:opentrons/opentrons_flex_96_tiprack_1000ul/1", "strategy": "usingGripper", diff --git a/protocol-designer/fixtures/protocol/8/example_1_1_0MigratedToV8.json b/protocol-designer/fixtures/protocol/8/example_1_1_0MigratedToV8.json index 56b9885aea9..c789d62cacc 100644 --- a/protocol-designer/fixtures/protocol/8/example_1_1_0MigratedToV8.json +++ b/protocol-designer/fixtures/protocol/8/example_1_1_0MigratedToV8.json @@ -6,7 +6,7 @@ "author": "Author name", "description": "Description here", "created": 1560957631666, - "lastModified": 1711902162091, + "lastModified": 1714570455185, "category": null, "subcategory": null, "tags": [] @@ -15,10 +15,10 @@ "name": "opentrons/protocol-designer", "version": "8.1.0", "data": { - "_internalAppBuildDate": "Sun, 31 Mar 2024 16:22:18 GMT", + "_internalAppBuildDate": "Wed, 01 May 2024 13:32:34 GMT", "defaultValues": { "aspirate_mmFromBottom": 1, - "dispense_mmFromBottom": 0.5, + "dispense_mmFromBottom": 1, "touchTip_mmFromTop": -1, "blowout_mmFromTop": 0 }, @@ -75,7 +75,7 @@ "e7d36200-92a5-11e9-ac62-1b173f839d9e": { "pipette": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": "6", - "tipRack": "c6f4ec70-92a5-11e9-ac62-1b173f839d9e:tiprack-10ul", + "tipRack": "opentrons/opentrons_96_tiprack_10ul/1", "changeTip": "always", "path": "single", "aspirate_wells_grouped": false, @@ -114,7 +114,6 @@ "disposalVolume_checkbox": true, "disposalVolume_volume": "1", "blowout_checkbox": true, - "blowout_z_offset": 0, "blowout_location": "9b1c0d01-9d4f-4016-afe6-9e08b46acf5e:trashBin", "preWetTip": false, "aspirate_airGap_checkbox": false, @@ -133,6 +132,8 @@ "dispense_y_position": 0, "aspirate_x_position": 0, "aspirate_y_position": 0, + "blowout_z_offset": 0, + "blowout_flowRate": 1000, "id": "e7d36200-92a5-11e9-ac62-1b173f839d9e", "stepType": "moveLiquid", "stepName": "transfer things", @@ -144,7 +145,6 @@ "labware": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", "mix_wellOrder_first": "t2b", "mix_wellOrder_second": "l2r", - "blowout_z_offset": 0, "blowout_checkbox": true, "blowout_location": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", "mix_mmFromBottom": 0.5, @@ -161,9 +161,11 @@ "mix_touchTip_mmFromBottom": 30.5, "dropTip_location": "9b1c0d01-9d4f-4016-afe6-9e08b46acf5e:trashBin", "nozzles": null, - "tipRack": "c6f4ec70-92a5-11e9-ac62-1b173f839d9e:tiprack-10ul", + "tipRack": "opentrons/opentrons_96_tiprack_10ul/1", "mix_x_position": 0, "mix_y_position": 0, + "blowout_z_offset": 0, + "blowout_flowRate": 1000, "id": "18113c80-92a6-11e9-ac62-1b173f839d9e", "stepType": "mix", "stepName": "mix", @@ -3344,7 +3346,7 @@ "commandSchemaId": "opentronsCommandSchemaV8", "commands": [ { - "key": "818878e2-9a2b-498e-be2d-1d317f6f7af8", + "key": "f6753216-417b-49fa-88cc-e359adae26f6", "commandType": "loadPipette", "params": { "pipetteName": "p10_single", @@ -3353,7 +3355,7 @@ } }, { - "key": "1ae8e180-58c4-4970-b372-9a8f1869f297", + "key": "aeec3001-087f-4074-b098-9dfdb465e008", "commandType": "loadPipette", "params": { "pipetteName": "p50_single", @@ -3362,7 +3364,7 @@ } }, { - "key": "ce9f8375-8577-4062-a9ff-12bc33d3bec5", + "key": "c540d35e-88e1-49da-aa90-5f9cbcd9068f", "commandType": "loadLabware", "params": { "displayName": "tiprack 10ul (1)", @@ -3374,7 +3376,7 @@ } }, { - "key": "8f2f7622-476b-40ff-b692-768a69158aa2", + "key": "827e73cf-2870-43d6-aa0b-5ac87d8996c4", "commandType": "loadLabware", "params": { "displayName": "tiprack 200ul (1)", @@ -3386,7 +3388,7 @@ } }, { - "key": "6802ec5e-204e-4a63-87a9-c6066788e537", + "key": "c519abb5-64ae-4068-bcb7-198e29e865e0", "commandType": "loadLabware", "params": { "displayName": "96 deep well (1)", @@ -3399,7 +3401,7 @@ }, { "commandType": "loadLiquid", - "key": "c63af547-a330-4e04-96ea-f04ef3c93ca1", + "key": "ae991255-3f64-47be-a541-cbe63e0ef907", "params": { "liquidId": "1", "labwareId": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", @@ -3408,7 +3410,7 @@ }, { "commandType": "loadLiquid", - "key": "d1af9a18-bb2f-4929-b952-7b1e21eadac8", + "key": "1b2418da-a26d-4cb3-9578-17782cf79f1b", "params": { "liquidId": "0", "labwareId": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", @@ -3423,7 +3425,7 @@ }, { "commandType": "pickUpTip", - "key": "24f9ab3b-48fd-42cb-8e0d-2128427459fe", + "key": "3e69c4c9-2255-4043-b548-1b9c410360aa", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "c6f4ec70-92a5-11e9-ac62-1b173f839d9e:tiprack-10ul", @@ -3432,7 +3434,7 @@ }, { "commandType": "aspirate", - "key": "426ca672-56a0-430d-bdba-23632ad728b0", + "key": "9ce167a0-b022-45cf-bc14-d3ec56381d9d", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -3447,7 +3449,7 @@ }, { "commandType": "dispense", - "key": "ea2eab58-723d-462e-ae8b-d0daa9462ece", + "key": "85330ac5-e850-47d3-8089-b38866d4a2d0", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -3462,7 +3464,7 @@ }, { "commandType": "aspirate", - "key": "fa061fa1-e5d5-42cf-b9dd-d4b9a6b6eabe", + "key": "1db1dfc0-62db-4d89-9de5-3d2fa230ff07", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -3477,7 +3479,7 @@ }, { "commandType": "dispense", - "key": "1e21ebe5-4e6f-4bc5-8dc3-1f1aa9158ff5", + "key": "1a39e7f0-8a76-4936-ac5d-114f8c10ae91", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -3492,7 +3494,7 @@ }, { "commandType": "aspirate", - "key": "7ad7bdad-84eb-42a0-b4ac-48949808a041", + "key": "496b2ad5-b4da-4259-be84-8b441d0a4b60", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -3507,7 +3509,7 @@ }, { "commandType": "dispense", - "key": "dd723bb6-9eba-4ab6-bc80-03f6f6db17df", + "key": "93ab5d06-a448-45b3-a276-272edfd91873", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -3522,7 +3524,7 @@ }, { "commandType": "aspirate", - "key": "eddfcde7-5497-42e7-bff4-56d2052bc552", + "key": "3d0984ed-5b02-4d38-912e-10c031b55ee0", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 6, @@ -3537,7 +3539,7 @@ }, { "commandType": "touchTip", - "key": "e3e8b3d6-a118-43de-9155-7d1a1da67dbd", + "key": "4d66aa3a-446e-400f-a24a-ac34accfbc3b", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", @@ -3547,7 +3549,7 @@ }, { "commandType": "dispense", - "key": "080a9a26-92ba-48ba-84ed-0a10743b7918", + "key": "d6f1e7d9-d050-46e0-9403-d7ab6ac26ffb", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 6, @@ -3562,7 +3564,7 @@ }, { "commandType": "aspirate", - "key": "ac6f0caf-5fe8-4d45-9659-1265fd022295", + "key": "10b51ab7-5889-447a-a992-b74734023f81", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -3577,7 +3579,7 @@ }, { "commandType": "dispense", - "key": "b9e03bec-0741-4dc9-b953-cadd7e7c40b6", + "key": "caa702df-9c41-421a-8c98-76d9d7f95889", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -3592,7 +3594,7 @@ }, { "commandType": "aspirate", - "key": "017fd13a-0e3a-4f54-94c3-8d5fc8eb4ba4", + "key": "cb96c8d0-5f14-484b-80fc-60753c2c6b14", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -3607,7 +3609,7 @@ }, { "commandType": "dispense", - "key": "7961e88d-1b9b-4615-bcbd-31320a03f81c", + "key": "a7ddff78-c39b-4fb0-9db6-cdadea58a4e2", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -3622,7 +3624,7 @@ }, { "commandType": "moveToAddressableArea", - "key": "4d60aa9f-e59b-491a-b494-aef4b877f6fa", + "key": "80b7c947-e20f-4331-9b87-2c7bebebfa07", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "addressableAreaName": "fixedTrash", @@ -3631,7 +3633,7 @@ }, { "commandType": "blowOutInPlace", - "key": "8bf8312b-7058-430e-8344-84ed35dda280", + "key": "e26b883d-9bb2-49e2-9a26-62626eb04e04", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "flowRate": 1000 @@ -3639,7 +3641,7 @@ }, { "commandType": "touchTip", - "key": "728468cd-08a9-4811-b5a8-ce0649835d29", + "key": "87a0b1e4-f375-4dee-9597-87f8f15b8c25", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", @@ -3649,7 +3651,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "1b5e20e3-85d5-4d87-89f9-7d9568696f6d", + "key": "268d8310-7f0a-4545-a8ed-ef2fb22a3085", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "addressableAreaName": "fixedTrash", @@ -3659,12 +3661,12 @@ }, { "commandType": "dropTipInPlace", - "key": "3f520a13-6e4f-4ade-bbf8-2fdd35b875c3", + "key": "abbc727f-81d6-4b5d-8a52-cd8f966e8fbf", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e" } }, { "commandType": "pickUpTip", - "key": "4b8db7a7-609e-431a-bf9d-7cf858c4b8f7", + "key": "292c5f17-65f9-4af7-88fd-33c012df2059", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "c6f4ec70-92a5-11e9-ac62-1b173f839d9e:tiprack-10ul", @@ -3673,7 +3675,7 @@ }, { "commandType": "aspirate", - "key": "0355948e-57ca-4572-baa5-7a64b7ef28cc", + "key": "1bb202e6-007b-4631-8aa0-5f5211c263fc", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -3688,7 +3690,7 @@ }, { "commandType": "dispense", - "key": "193a745f-0698-4427-8d0d-d1e4fe24de24", + "key": "cdf0ab85-fdd3-41ab-89f7-5c7b696c48dd", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -3703,7 +3705,7 @@ }, { "commandType": "aspirate", - "key": "8d205199-aa0a-4640-9a23-b3adcca61be2", + "key": "b8d9161d-0835-44b3-8223-73fa752a5a5a", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -3718,7 +3720,7 @@ }, { "commandType": "dispense", - "key": "fe86a1bb-8c8e-4307-b06e-c92a8e231679", + "key": "33c2f20d-6d68-4b63-a812-7f40735bbaaa", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -3733,7 +3735,7 @@ }, { "commandType": "aspirate", - "key": "1976e9d0-ee3f-4ca0-a039-147dd8c21399", + "key": "95d4ac3a-8094-46fc-9c30-275f37701e3f", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -3748,7 +3750,7 @@ }, { "commandType": "dispense", - "key": "b75876f5-cbf6-43ae-8bb5-1b71641ccc6a", + "key": "cef01434-9fa2-48dd-8139-755a0d5f5568", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -3763,7 +3765,7 @@ }, { "commandType": "aspirate", - "key": "c6ff48bc-a06c-4e5b-9172-986375d8a934", + "key": "67786140-5e0b-4290-a448-925cec83c85c", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 6, @@ -3778,7 +3780,7 @@ }, { "commandType": "touchTip", - "key": "7a15666d-4676-41b5-8752-26cc8a07f17e", + "key": "4f6e1cc6-67be-49ab-814d-d7534a0da726", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", @@ -3788,7 +3790,7 @@ }, { "commandType": "dispense", - "key": "ec56b383-c163-402e-9996-d4cc69a1cffd", + "key": "7b33de85-68cb-4888-8023-8be805f5a77a", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 6, @@ -3803,7 +3805,7 @@ }, { "commandType": "aspirate", - "key": "cabfdd05-1309-43e2-bfbd-d04bc7de85c9", + "key": "13c080bb-8e30-41c9-a237-e2591f09ee3c", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -3818,7 +3820,7 @@ }, { "commandType": "dispense", - "key": "05cb631d-9092-46e9-b802-6175fbae1e1f", + "key": "61c081de-e44b-4583-b963-89be8985723f", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -3833,7 +3835,7 @@ }, { "commandType": "aspirate", - "key": "ea50ada1-23d9-4ecf-af9d-3246930afd26", + "key": "63421ac3-10f1-4472-b813-2cce280b2ddc", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -3848,7 +3850,7 @@ }, { "commandType": "dispense", - "key": "2523b9ed-ef76-40c9-8947-18c039e50939", + "key": "56253d18-7874-44ab-83a5-bb39c3c306e8", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -3863,7 +3865,7 @@ }, { "commandType": "moveToAddressableArea", - "key": "58c4751a-5628-4596-a171-1ac260259c28", + "key": "f7030e97-02d3-46c0-9275-d53932064855", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "addressableAreaName": "fixedTrash", @@ -3872,7 +3874,7 @@ }, { "commandType": "blowOutInPlace", - "key": "ba5016a9-cd7a-41c8-bf17-aadb64664190", + "key": "1a5179e1-6ec6-4028-9b13-32bae277e68e", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "flowRate": 1000 @@ -3880,7 +3882,7 @@ }, { "commandType": "touchTip", - "key": "1314e2d9-8d46-4663-9bf3-458a300b0add", + "key": "aa2fa938-b38e-4d92-a4c5-0123131b29a7", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", @@ -3890,7 +3892,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "8527d992-4185-4f20-99a9-864541aaa7b6", + "key": "c90e2918-1615-4d2a-b7a0-daaa013e2a42", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "addressableAreaName": "fixedTrash", @@ -3900,12 +3902,12 @@ }, { "commandType": "dropTipInPlace", - "key": "8c564bbd-34dd-44d2-ace8-995097f571b9", + "key": "220b1148-9a8f-4826-b515-6a2e87419f4c", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e" } }, { "commandType": "pickUpTip", - "key": "5377f188-8a31-4ff3-8ed3-ff5b651e467b", + "key": "001b95fd-fd21-425a-8846-432768900785", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "c6f4ec70-92a5-11e9-ac62-1b173f839d9e:tiprack-10ul", @@ -3914,7 +3916,7 @@ }, { "commandType": "aspirate", - "key": "70c291fd-f5c9-4216-9446-de8191fff376", + "key": "a1e24a66-7c37-40d8-8415-9ae9ce1107b5", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -3929,7 +3931,7 @@ }, { "commandType": "dispense", - "key": "7f1299ec-8930-457d-a2d9-c18876da3769", + "key": "42b2126b-b283-469f-b3f9-dfa2b78c5958", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -3944,7 +3946,7 @@ }, { "commandType": "aspirate", - "key": "d04dee6f-90a4-4b4b-89b8-05f1104431fd", + "key": "b73d2141-34cd-4cd0-828a-6640f6f75ded", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -3959,7 +3961,7 @@ }, { "commandType": "dispense", - "key": "c983ed9b-783b-411a-8df2-50ef254b4deb", + "key": "ad64a163-5293-4b98-89df-28766993bf09", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -3974,7 +3976,7 @@ }, { "commandType": "aspirate", - "key": "678dc318-94d9-488b-b2e3-f04ed29a2863", + "key": "b514ff83-cd73-41ee-8d08-9862e6989924", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -3989,7 +3991,7 @@ }, { "commandType": "dispense", - "key": "6aee8385-14b4-48fa-bef0-3a642d38c1cd", + "key": "0d5bba7e-ac6a-48a6-82f0-cb46cdc0d5cd", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4004,7 +4006,7 @@ }, { "commandType": "aspirate", - "key": "c9e9500e-5c89-450c-a56e-7058720a74ce", + "key": "c20937ce-e7d3-4f45-9e71-80d6c8439a08", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 6, @@ -4019,7 +4021,7 @@ }, { "commandType": "touchTip", - "key": "eeabdbf7-0dda-4246-859f-de8b643184c0", + "key": "ee7d026d-e7fa-4027-8ba8-8ac575ea7ead", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", @@ -4029,7 +4031,7 @@ }, { "commandType": "dispense", - "key": "60f965e4-60af-4183-99de-15c77232416d", + "key": "fe445e71-616e-42a1-ac92-3b2dd37ac7f1", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 6, @@ -4044,7 +4046,7 @@ }, { "commandType": "aspirate", - "key": "7a40b467-9754-4c02-ae2e-4644cb997555", + "key": "4ebe6cc3-442a-4a2c-80ba-9dee24865d15", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -4059,7 +4061,7 @@ }, { "commandType": "dispense", - "key": "a24675b2-41c7-4908-97ce-6bcf04c3d149", + "key": "092fcbe7-cd36-4077-8ab4-7e7b3ee5e2d2", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -4074,7 +4076,7 @@ }, { "commandType": "aspirate", - "key": "71a467a6-4c67-46e1-b829-f9a02fb6669e", + "key": "27d6abf5-7f62-441c-aab3-fb0d0d68bf3a", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -4089,7 +4091,7 @@ }, { "commandType": "dispense", - "key": "b58fb6c6-17f0-44cf-add2-5ad3a99a06fe", + "key": "3acb966b-898d-43bb-a212-f23a9351fb00", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -4104,7 +4106,7 @@ }, { "commandType": "moveToAddressableArea", - "key": "b97a7e69-13c0-444b-9405-c84d8ab431bf", + "key": "10f4ee73-f68b-45c9-a2cb-e4826433e952", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "addressableAreaName": "fixedTrash", @@ -4113,7 +4115,7 @@ }, { "commandType": "blowOutInPlace", - "key": "7e767220-28ab-4b59-ae54-1df3a59ac491", + "key": "5d40f966-01f9-441e-b16f-05782f0a6921", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "flowRate": 1000 @@ -4121,7 +4123,7 @@ }, { "commandType": "touchTip", - "key": "a4329dfb-0547-498b-a132-5314bdc37453", + "key": "e79182b7-eb3d-4421-b6a5-73e3f7e9df54", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", @@ -4131,7 +4133,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "222528ae-afc3-459f-bd12-291fb6e92977", + "key": "11dd25c1-64f6-47b3-ba17-1f8d4c85b30f", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "addressableAreaName": "fixedTrash", @@ -4141,12 +4143,12 @@ }, { "commandType": "dropTipInPlace", - "key": "a2b1c413-6b6d-4db7-b39f-36e801bb67bf", + "key": "c2d99c79-fa4b-448b-ab79-c5ea22d3b5db", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e" } }, { "commandType": "pickUpTip", - "key": "ee7cca8e-9d5a-4308-b437-91b3ac59e95c", + "key": "70a9d1cf-db05-4510-9219-d0e18e0ceab6", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "c6f4ec70-92a5-11e9-ac62-1b173f839d9e:tiprack-10ul", @@ -4155,7 +4157,7 @@ }, { "commandType": "aspirate", - "key": "9c65eb65-086b-4535-8dd4-fcdc3b1ce711", + "key": "88a00826-d936-495b-81a0-08b2db4b0cbd", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4170,7 +4172,7 @@ }, { "commandType": "dispense", - "key": "de99e84e-c816-42d7-bbaf-c685cf196c84", + "key": "e62b965a-6150-4857-81a4-83808731bb63", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4185,7 +4187,7 @@ }, { "commandType": "aspirate", - "key": "2bb3b611-e413-4866-9f88-2093be26c559", + "key": "dfd3261d-d508-45db-bc07-4b66aab7f4ee", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4200,7 +4202,7 @@ }, { "commandType": "dispense", - "key": "51c61ed1-215a-4304-b0bc-f7c0787d9759", + "key": "fd6702e4-1dc4-42b3-a479-ccd252df34b7", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4215,7 +4217,7 @@ }, { "commandType": "aspirate", - "key": "a5cb7070-9db9-4d93-94a0-baafdb9e1246", + "key": "4a5703bb-d4fd-431f-9c3c-928fd654d667", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4230,7 +4232,7 @@ }, { "commandType": "dispense", - "key": "b4812aa0-2c04-4f9f-a060-dcddb31655eb", + "key": "cd9e2d71-2f8d-4a3e-beb5-664df5b40ed4", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4245,7 +4247,7 @@ }, { "commandType": "aspirate", - "key": "09657153-451a-4ce8-a0aa-d238e97b5d4a", + "key": "f43a5ddf-41e8-4763-a897-5463be83a450", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 6, @@ -4260,7 +4262,7 @@ }, { "commandType": "touchTip", - "key": "1ba61ffa-26f7-4258-806e-459483f8aee2", + "key": "9a38f25f-8e70-4e48-906f-5ad8549f97a9", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", @@ -4270,7 +4272,7 @@ }, { "commandType": "dispense", - "key": "3e54188d-9608-4976-b2a8-0262bc6cd9a8", + "key": "356a5ed5-4055-434b-925e-dc9d74b86916", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 6, @@ -4285,7 +4287,7 @@ }, { "commandType": "aspirate", - "key": "12abbaa6-4354-4635-86c7-53da228b89e9", + "key": "83147cc6-40bd-4d31-8d7c-cebc82587da2", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -4300,7 +4302,7 @@ }, { "commandType": "dispense", - "key": "75989dac-fb90-46e0-8510-05946f0bb820", + "key": "e48e7e86-5bcf-411f-85aa-fd880047317d", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -4315,7 +4317,7 @@ }, { "commandType": "aspirate", - "key": "970cd398-3ad1-46ee-a917-9781c74964c8", + "key": "3ed7361d-167a-4624-90e7-be018382c29d", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -4330,7 +4332,7 @@ }, { "commandType": "dispense", - "key": "224042a5-8347-4867-b30c-ea349eee0eb0", + "key": "edcad86c-128a-4b11-b3f6-c00af215f751", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -4345,7 +4347,7 @@ }, { "commandType": "moveToAddressableArea", - "key": "5bca8d87-fae2-4082-92f1-5da5e9b0b01a", + "key": "f524c6b9-a2c8-4e20-8088-ebc799e37701", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "addressableAreaName": "fixedTrash", @@ -4354,7 +4356,7 @@ }, { "commandType": "blowOutInPlace", - "key": "6a40c11f-2894-4c0d-ae8c-3069aa7a3ac6", + "key": "017496c5-bfda-45b4-a70d-cae13a05406f", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "flowRate": 1000 @@ -4362,7 +4364,7 @@ }, { "commandType": "touchTip", - "key": "9667d8ab-87f8-4af8-a61c-39fa46e15928", + "key": "88956734-eece-42e3-a7d8-8d759f9de247", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", @@ -4372,7 +4374,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "54efaffe-8b67-45b0-8a1b-34eb9929230b", + "key": "c5550d27-fdd6-43c9-a876-aa3e50489707", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "addressableAreaName": "fixedTrash", @@ -4382,12 +4384,12 @@ }, { "commandType": "dropTipInPlace", - "key": "4732e9c8-8b22-447d-9e8a-04360782f50c", + "key": "9eaf32a8-bdec-434e-a644-22f6bba08a6b", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e" } }, { "commandType": "pickUpTip", - "key": "55fbea4b-e8d2-4cc9-84f1-e531eedc46c8", + "key": "ecb5d2d9-7e63-43b0-b8b9-5464c9478ed0", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "c6f4ec70-92a5-11e9-ac62-1b173f839d9e:tiprack-10ul", @@ -4396,7 +4398,7 @@ }, { "commandType": "aspirate", - "key": "d735d944-73ff-4713-ac51-c1341e5cc1a9", + "key": "09671823-b2bf-4803-8b7f-d21f37e064bb", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4411,7 +4413,7 @@ }, { "commandType": "dispense", - "key": "33e8c95b-801c-42c3-9048-fa14b6aa7f29", + "key": "05adf9ce-7912-44ec-8639-248408431a8d", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4426,7 +4428,7 @@ }, { "commandType": "aspirate", - "key": "b25b278a-8b01-4bc2-a1f8-456c7bf8c526", + "key": "91630cc1-d209-4c82-ba0d-cc0a16a8b24f", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4441,7 +4443,7 @@ }, { "commandType": "dispense", - "key": "23d673c8-d769-480b-858b-43ac62636220", + "key": "94f28a06-4afd-4bde-809f-33a6ef4c4479", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4456,7 +4458,7 @@ }, { "commandType": "aspirate", - "key": "3452e515-d862-40d0-99e1-34dd0404337f", + "key": "cf37f60a-7f87-483d-ae7d-b637273a9f65", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4471,7 +4473,7 @@ }, { "commandType": "dispense", - "key": "36c73f15-d9cd-410c-8699-f19396584618", + "key": "dae3c16b-f335-4f48-8fa0-f7304d986601", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4486,7 +4488,7 @@ }, { "commandType": "aspirate", - "key": "7b78234d-4513-49cc-83e7-10b662ff8675", + "key": "91698561-8c9a-43a6-be0e-48fc7169be0c", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 6, @@ -4501,7 +4503,7 @@ }, { "commandType": "touchTip", - "key": "b1b3ee6f-a9be-4220-8004-7296970de788", + "key": "0a0d2b0f-de56-41dd-b69b-901ff5899ac9", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", @@ -4511,7 +4513,7 @@ }, { "commandType": "dispense", - "key": "f7c5a31f-1a71-478f-a145-eb5c5c567c6d", + "key": "8f9ab04c-96e7-4e9d-9a19-5075e18519a6", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 6, @@ -4526,7 +4528,7 @@ }, { "commandType": "aspirate", - "key": "5e4a8c3c-5a80-488b-898d-d1074f2c426c", + "key": "03610238-537c-4b82-8c6d-fa101cae4631", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -4541,7 +4543,7 @@ }, { "commandType": "dispense", - "key": "da0e8d29-8619-47e1-b8da-98ccaf2c56fc", + "key": "071af969-3818-4807-9fd7-26cd00945ab0", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -4556,7 +4558,7 @@ }, { "commandType": "aspirate", - "key": "3fd622c1-93bc-4e5d-92cb-3dc40f38d92d", + "key": "ff423f6d-35ef-4ecd-bf8f-435776a5a3b2", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -4571,7 +4573,7 @@ }, { "commandType": "dispense", - "key": "7fe8ecbf-6872-4c45-9f41-b3f5e31b8c42", + "key": "44d4dacd-8cac-4961-892e-cda32094f127", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -4586,7 +4588,7 @@ }, { "commandType": "moveToAddressableArea", - "key": "7e7f40a5-1b19-414d-b1ec-b0f632ee81eb", + "key": "53b1ccc5-7b58-4d48-b8fd-0c6ac738b4d1", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "addressableAreaName": "fixedTrash", @@ -4595,7 +4597,7 @@ }, { "commandType": "blowOutInPlace", - "key": "e7d928ca-d918-43a1-973a-e56361029dcd", + "key": "c812e493-c61f-4719-a31f-ac74b2019c54", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "flowRate": 1000 @@ -4603,7 +4605,7 @@ }, { "commandType": "touchTip", - "key": "1665f0f5-1778-49ed-a765-bcdcc3a9c13a", + "key": "ac2ff63c-9b28-4835-89aa-22d3c1edfca8", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", @@ -4613,7 +4615,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "5f71c216-2dd4-4b3f-9958-feac1e0ba419", + "key": "8f6ec1bb-1f7f-49e7-8830-0881bd980638", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "addressableAreaName": "fixedTrash", @@ -4623,12 +4625,12 @@ }, { "commandType": "dropTipInPlace", - "key": "0d98fee0-4ada-4ddd-98cc-ee4f51763615", + "key": "749b4670-f63f-4377-bae9-57e1115f6756", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e" } }, { "commandType": "pickUpTip", - "key": "1eca1b12-6dda-4a57-84cc-48ed09a5dcc7", + "key": "38da00e9-f4aa-4e74-b377-b19d635f62a8", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "c6f4ec70-92a5-11e9-ac62-1b173f839d9e:tiprack-10ul", @@ -4637,7 +4639,7 @@ }, { "commandType": "aspirate", - "key": "6468842b-d755-431a-8f39-63390afc45aa", + "key": "c8dad345-cf97-45ef-95a5-13ab38df4734", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4652,7 +4654,7 @@ }, { "commandType": "dispense", - "key": "3f19926d-5262-4869-8830-7eb13951f4fe", + "key": "b6f8c5d0-1348-4eff-a0e5-e90cd5a0b34b", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4667,7 +4669,7 @@ }, { "commandType": "aspirate", - "key": "0816f07a-7ddf-41da-91a8-6c55bcf902ff", + "key": "662d7128-430c-46aa-ab97-348de5ae1b59", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4682,7 +4684,7 @@ }, { "commandType": "dispense", - "key": "6ac9d9b6-b45e-4b0a-90c5-835a680ab914", + "key": "08d301f7-b6b8-46f8-983f-3e33e5727c25", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4697,7 +4699,7 @@ }, { "commandType": "aspirate", - "key": "2c0b977d-cc77-44bb-b0a3-62339279f8d4", + "key": "24bbc121-f08f-42e4-8a4d-37a88bca03c7", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4712,7 +4714,7 @@ }, { "commandType": "dispense", - "key": "b15ab048-c8ae-491b-ba0a-ddb84af43b8a", + "key": "9d07468c-42c4-41c9-a67e-3fdeac16fa0b", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4727,7 +4729,7 @@ }, { "commandType": "aspirate", - "key": "ebb52c59-bc4d-4f3a-b1b4-10ceea23ecd4", + "key": "44cc4edd-ff47-487c-ac33-9815b9af3ae9", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 6, @@ -4742,7 +4744,7 @@ }, { "commandType": "touchTip", - "key": "1c48b0b0-c786-4278-a95b-180d8bc8d7fb", + "key": "5f0a3727-1976-4927-852b-8fee2e8cff77", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", @@ -4752,7 +4754,7 @@ }, { "commandType": "dispense", - "key": "6db1da99-4bfc-4723-a37b-db57a913a5a0", + "key": "a69b2c7d-115d-4ffe-ac02-6b65b306411e", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 6, @@ -4767,7 +4769,7 @@ }, { "commandType": "aspirate", - "key": "b040900a-f61c-462e-9238-87746a45c0b8", + "key": "d8fc74ae-bbef-43b5-afcb-c04c86f98b71", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -4782,7 +4784,7 @@ }, { "commandType": "dispense", - "key": "8e2de19c-a6b1-4af7-a614-8f692815d667", + "key": "4d83b666-8df0-47cb-8cca-5bb9532e21b0", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -4797,7 +4799,7 @@ }, { "commandType": "aspirate", - "key": "a72f4e61-2874-4af0-a471-d97434970e2b", + "key": "984cc219-9237-49b9-a775-93589e5a66ae", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -4812,7 +4814,7 @@ }, { "commandType": "dispense", - "key": "ff833f33-6c7e-417a-8293-f9a2c2eead8c", + "key": "a45e7f3f-64d4-4dc9-aab3-10a6d2c38660", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -4827,7 +4829,7 @@ }, { "commandType": "moveToAddressableArea", - "key": "40d74de4-9953-43ae-b4bc-518d39005303", + "key": "e440bc8d-adbd-47c9-b0b9-2432a13f8664", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "addressableAreaName": "fixedTrash", @@ -4836,7 +4838,7 @@ }, { "commandType": "blowOutInPlace", - "key": "7570e6a2-b2a3-4836-aaa0-13c90ceb08f4", + "key": "f78482cb-1663-43ca-ad28-2aa0f9c1e926", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "flowRate": 1000 @@ -4844,7 +4846,7 @@ }, { "commandType": "touchTip", - "key": "5de67294-430d-4856-aa25-0177b32ef514", + "key": "f7ef1b94-cceb-4ae8-9a22-65b1a7339438", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", @@ -4854,7 +4856,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "b25ac8f3-fe61-4f87-b5f2-40936132a6dd", + "key": "50ca2b65-11fe-4b52-bfc6-60efba9a6445", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "addressableAreaName": "fixedTrash", @@ -4864,12 +4866,12 @@ }, { "commandType": "dropTipInPlace", - "key": "aa3d17b8-8d52-462f-9e39-b0d2d83e5407", + "key": "1dc894fa-effa-4b0a-b1a4-50766e1a9454", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e" } }, { "commandType": "pickUpTip", - "key": "188da1f2-486b-4dfd-b2c8-e0903544fa8d", + "key": "2c14e46f-4257-485a-abd9-a6fa88233d08", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "c6f4ec70-92a5-11e9-ac62-1b173f839d9e:tiprack-10ul", @@ -4878,7 +4880,7 @@ }, { "commandType": "aspirate", - "key": "df11a136-0f66-4502-ad52-443adc71ca2b", + "key": "a75ee83e-f86a-4ba7-8982-1e67573eebc5", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4893,7 +4895,7 @@ }, { "commandType": "dispense", - "key": "00502ab3-b649-4532-ba39-184ff41b00cb", + "key": "93d11701-ab94-4693-bd67-2c9a5b8ca905", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4908,7 +4910,7 @@ }, { "commandType": "aspirate", - "key": "cdc0749e-e66b-480e-afe0-3ad6c5e739e4", + "key": "618e28e9-06d3-40ed-af8c-beebf2b230ed", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4923,7 +4925,7 @@ }, { "commandType": "dispense", - "key": "65529980-e475-4f51-a8dc-cd1f7e5a5020", + "key": "8096ab04-2d76-4c5c-ba8c-c3eb0791ac16", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4938,7 +4940,7 @@ }, { "commandType": "aspirate", - "key": "d9e94497-0439-4675-bb57-cc2e62ea7a84", + "key": "d7f16642-48b2-44e8-990c-d152f2e3effd", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4953,7 +4955,7 @@ }, { "commandType": "dispense", - "key": "27bd35c9-4ef4-471f-954b-289db56992ad", + "key": "20c1fb9e-82ff-4329-8e06-bbf3b69312f5", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -4968,7 +4970,7 @@ }, { "commandType": "aspirate", - "key": "9241c560-e1d0-4468-ac78-10c9511d0113", + "key": "a7904076-7aa5-4af0-9b33-0b782e4c574b", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 6, @@ -4983,7 +4985,7 @@ }, { "commandType": "touchTip", - "key": "67e511d9-8198-4c0d-808e-c9600f2aff6b", + "key": "f8314e7a-2934-4f37-87ff-df93adee027c", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", @@ -4993,7 +4995,7 @@ }, { "commandType": "dispense", - "key": "ea876b75-dbb7-445e-afb4-efa1fd12eda8", + "key": "5261a98e-b9ef-4654-be05-63bd6d625b95", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 6, @@ -5008,7 +5010,7 @@ }, { "commandType": "aspirate", - "key": "7551fb8d-3899-42f4-ba52-9e03c2410ae5", + "key": "2d7e6164-5ff0-474f-8793-bed55e9268f6", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -5023,7 +5025,7 @@ }, { "commandType": "dispense", - "key": "dae940af-8337-439f-83c5-39745994b216", + "key": "b1d778c2-7c4b-4989-9819-4f70959bf690", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -5038,7 +5040,7 @@ }, { "commandType": "aspirate", - "key": "d9c4b87f-8e3f-415b-9c61-b14cff73fa6e", + "key": "2da23b46-c32e-45a9-93b4-e6ba54209279", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -5053,7 +5055,7 @@ }, { "commandType": "dispense", - "key": "6e1ae4be-0622-490d-811a-1442a54f38c6", + "key": "c0f8e9a6-704d-409e-86c6-cdfece6d75cf", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -5068,7 +5070,7 @@ }, { "commandType": "moveToAddressableArea", - "key": "2172c551-8f66-49ec-b092-3cecb3ecd1e6", + "key": "f9669e2a-89c9-4e89-b11a-792ca9372110", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "addressableAreaName": "fixedTrash", @@ -5077,7 +5079,7 @@ }, { "commandType": "blowOutInPlace", - "key": "70f94de0-45c2-4082-85c7-000a3c7d4e05", + "key": "76f1f9d1-5ed9-4fe9-ac86-e44b8669bcef", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "flowRate": 1000 @@ -5085,7 +5087,7 @@ }, { "commandType": "touchTip", - "key": "7a8c6027-3547-4415-97e2-e4a8839cefcb", + "key": "44c1606d-102c-4b0e-9af4-27719c14bf25", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", @@ -5095,7 +5097,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "9e76549d-de35-4be7-b42f-83e81eb148e5", + "key": "e8d9bb09-8188-46d1-bb5b-2fe490c85243", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "addressableAreaName": "fixedTrash", @@ -5105,12 +5107,12 @@ }, { "commandType": "dropTipInPlace", - "key": "edb7a124-0334-41a3-b82f-237bf2a63e37", + "key": "4e5f18e9-9192-46eb-932f-0dcf604c4649", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e" } }, { "commandType": "pickUpTip", - "key": "f040345b-250f-4fa6-abc0-62e27fe59938", + "key": "52647b11-c226-4918-80ea-9bac8a02a373", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "c6f4ec70-92a5-11e9-ac62-1b173f839d9e:tiprack-10ul", @@ -5119,7 +5121,7 @@ }, { "commandType": "aspirate", - "key": "cd942842-7300-40c1-87a6-28f073ea3dc5", + "key": "e3239197-dbe6-4c71-917a-4fd41af8d75d", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -5134,7 +5136,7 @@ }, { "commandType": "dispense", - "key": "f6a45b15-269b-482d-983b-d3bc5db57d26", + "key": "01f40e1b-bdd0-4973-b2b8-ee4785ea9c6f", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -5149,7 +5151,7 @@ }, { "commandType": "aspirate", - "key": "7d61c0b4-4555-435c-b837-b559b360a82e", + "key": "5be5ae28-4e96-40dc-833c-60ac08044f96", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -5164,7 +5166,7 @@ }, { "commandType": "dispense", - "key": "9f9dfc52-5ca3-42e2-b9d5-3bfa8521de49", + "key": "001da4d7-697d-49b0-9654-8d0bdde1ac93", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -5179,7 +5181,7 @@ }, { "commandType": "aspirate", - "key": "11346b4b-af47-46f0-9461-52664eec0d39", + "key": "b4c0188b-ee1f-4859-9856-a7426109c2e3", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -5194,7 +5196,7 @@ }, { "commandType": "dispense", - "key": "23982cac-52ae-484f-b3e7-c52c029b1e9a", + "key": "00de49e0-d834-4458-9e4b-1a01ce5ed2c3", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -5209,7 +5211,7 @@ }, { "commandType": "aspirate", - "key": "148dd2de-1425-482f-8fec-32731007bbff", + "key": "5522605f-01b7-46a6-8f6a-2b51f0edc8ca", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 6, @@ -5224,7 +5226,7 @@ }, { "commandType": "touchTip", - "key": "41e664b1-6199-4a33-9857-76df944f516d", + "key": "9040c7b6-7714-48b9-94ad-b2d992287dad", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", @@ -5234,7 +5236,7 @@ }, { "commandType": "dispense", - "key": "152340ce-cde0-469e-9882-a8ef3d4a1cde", + "key": "8d65f1cf-058a-4666-8da5-403be4b98fed", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 6, @@ -5249,7 +5251,7 @@ }, { "commandType": "aspirate", - "key": "e4e8529f-89fc-4a94-a49d-410b799aa539", + "key": "b710f746-3424-40cb-80a0-c77bcaf03816", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -5264,7 +5266,7 @@ }, { "commandType": "dispense", - "key": "01461514-1395-4f09-95db-29dea71c1f5b", + "key": "a91072f7-47c9-4c85-8b43-491dc6d0b0be", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -5279,7 +5281,7 @@ }, { "commandType": "aspirate", - "key": "ff195ab9-cb65-45d1-93a8-a071d0bbed98", + "key": "6dc84887-b4b4-432c-87d8-92ab8431c127", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -5294,7 +5296,7 @@ }, { "commandType": "dispense", - "key": "8ba714b7-bcc2-48c3-8c57-0d0ac933b976", + "key": "b463a520-0c4c-4dbe-b5b9-330a35fcef55", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -5309,7 +5311,7 @@ }, { "commandType": "moveToAddressableArea", - "key": "8c2017b4-9145-46bc-a91f-83f27cc0a828", + "key": "9ba7bef1-dca0-43fe-b6e1-382a1e2dd958", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "addressableAreaName": "fixedTrash", @@ -5318,7 +5320,7 @@ }, { "commandType": "blowOutInPlace", - "key": "6dba0671-c83f-4fc2-8d9c-3e309448d0e9", + "key": "9f279224-1420-4f8f-a2ff-ac959fb45c42", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "flowRate": 1000 @@ -5326,7 +5328,7 @@ }, { "commandType": "touchTip", - "key": "15c49bf0-ce06-4687-aeb5-a5dd0736f2f5", + "key": "270a207d-7ad2-43bb-8392-11d68bde94ce", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", @@ -5336,7 +5338,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "5e494f88-ee95-42f1-bbd4-23b449649b93", + "key": "ad560eb4-0e24-4801-9a9f-aeaf7f21cb75", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "addressableAreaName": "fixedTrash", @@ -5346,12 +5348,12 @@ }, { "commandType": "dropTipInPlace", - "key": "e1f4d20a-b36c-4da1-9b1f-529aef638f1f", + "key": "ebdaf15a-14d8-4527-9dc8-0b1027009ee9", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e" } }, { "commandType": "pickUpTip", - "key": "c3d944d3-abe8-4f4c-8e4d-70792c3303f2", + "key": "7ffd9d57-22c6-40ca-85fb-8e0ab86c881a", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "c6f4ec70-92a5-11e9-ac62-1b173f839d9e:tiprack-10ul", @@ -5360,7 +5362,7 @@ }, { "commandType": "aspirate", - "key": "4432786d-94e4-4958-ae49-8d0679c97fc0", + "key": "7115280b-eea5-462f-aa18-815a876a9213", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -5375,7 +5377,7 @@ }, { "commandType": "dispense", - "key": "3efc13e5-aac5-4f23-b060-52003c8c827f", + "key": "5c04e6ab-5619-47e3-8421-49667b56ebc3", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -5390,7 +5392,7 @@ }, { "commandType": "aspirate", - "key": "5ec72861-9ac4-4a9b-91e2-907932819e58", + "key": "b065331a-9ce4-45a6-860a-9d8ae5eda44a", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -5405,7 +5407,7 @@ }, { "commandType": "dispense", - "key": "994b0746-ea15-4cfb-afa7-d00ff124e0f1", + "key": "2eaa51b7-ade3-43aa-8f84-d6e908d256fa", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -5420,7 +5422,7 @@ }, { "commandType": "aspirate", - "key": "2acee0bb-366c-4f1d-b165-f69a1c03b05f", + "key": "7af395d3-372b-44c8-89e2-cc7961567036", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -5435,7 +5437,7 @@ }, { "commandType": "dispense", - "key": "a44857c1-e5d2-4ce7-a428-41a68e426f3c", + "key": "25d443bc-3925-492d-9341-102d29aa125d", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 2, @@ -5450,7 +5452,7 @@ }, { "commandType": "aspirate", - "key": "09f55bdd-61ff-4667-878f-c79e0a21b9c5", + "key": "30a6ae71-1028-4137-b11f-7bd905b6bd74", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 6, @@ -5465,7 +5467,7 @@ }, { "commandType": "touchTip", - "key": "4daa0f4c-e10e-488e-9d19-3a8602a548f4", + "key": "5d318386-78b3-4b6e-998a-bfd61ce94e29", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", @@ -5475,7 +5477,7 @@ }, { "commandType": "dispense", - "key": "5f54be1c-fff2-41ae-b512-01a9bb28cc4a", + "key": "e2019112-8a64-4b03-9812-a0a840a7d035", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 6, @@ -5490,7 +5492,7 @@ }, { "commandType": "aspirate", - "key": "6e42ea13-01ed-461b-8dfa-9bd360982ddf", + "key": "09b49957-6e19-43a1-b402-9c1eed0857d4", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -5505,7 +5507,7 @@ }, { "commandType": "dispense", - "key": "63d6f42e-0caa-47c4-9341-e3a950f85128", + "key": "5f04a962-0466-4791-a019-4af5217a06f2", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -5520,7 +5522,7 @@ }, { "commandType": "aspirate", - "key": "c8791232-20bd-4068-a778-4630548b49ae", + "key": "b8c78bae-cc23-4415-9f63-fab416b2d674", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -5535,7 +5537,7 @@ }, { "commandType": "dispense", - "key": "98e4d5e2-4b75-435f-8809-099806e98694", + "key": "41c297e4-fa47-487d-9219-f4959d2b3f6a", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 3, @@ -5550,7 +5552,7 @@ }, { "commandType": "moveToAddressableArea", - "key": "921371a0-2df9-4f3e-b28f-0282399e98a3", + "key": "23137a5d-6b82-4ecc-9180-f1ebd051f54a", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "addressableAreaName": "fixedTrash", @@ -5559,7 +5561,7 @@ }, { "commandType": "blowOutInPlace", - "key": "f9c7ae2a-b401-4c92-8e6a-4366ffb93643", + "key": "3ec2c77d-bd1e-4aa6-b36f-37757218adee", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "flowRate": 1000 @@ -5567,7 +5569,7 @@ }, { "commandType": "touchTip", - "key": "70fbf7e3-cae6-49e7-bfd3-65a5376b5e3e", + "key": "10638801-4c1c-45d5-a61e-1160a9c4ddca", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", @@ -5577,7 +5579,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "74d53fee-f9c6-4a27-a54b-80a79e906b6c", + "key": "fcbf438c-40c0-4446-acae-d8f6ccce95e7", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "addressableAreaName": "fixedTrash", @@ -5587,12 +5589,12 @@ }, { "commandType": "dropTipInPlace", - "key": "28dc2329-937d-4d2c-8fc3-eecf3f321041", + "key": "cd3743de-0470-48bb-98f1-4c1cc9f05491", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e" } }, { "commandType": "pickUpTip", - "key": "5ad18635-8559-4904-8db4-4e2b19546238", + "key": "3fce8a1e-1857-4146-8a5d-296a06fa5101", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "c6f4ec70-92a5-11e9-ac62-1b173f839d9e:tiprack-10ul", @@ -5601,7 +5603,7 @@ }, { "commandType": "aspirate", - "key": "1227b40e-adda-4545-9724-5509ff790adf", + "key": "555deb27-6ccf-4f69-a22a-e88693869e01", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 5.5, @@ -5616,7 +5618,7 @@ }, { "commandType": "dispense", - "key": "b9c1000c-c52f-4b04-9790-9a2dec7dadd3", + "key": "c720bf94-d982-4989-8d05-5be11f5c56ac", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 5.5, @@ -5631,7 +5633,7 @@ }, { "commandType": "aspirate", - "key": "0b5da711-8961-40d0-a294-b4d9eed6c77a", + "key": "56079904-e3a0-4c8d-b302-8351c2f23cf9", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 5.5, @@ -5646,7 +5648,7 @@ }, { "commandType": "dispense", - "key": "12b3c883-f2b2-4651-816e-e38bb8cb5c85", + "key": "591975c1-bc72-456d-b186-2c5900e8990c", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 5.5, @@ -5661,7 +5663,7 @@ }, { "commandType": "aspirate", - "key": "b30463df-33e7-4038-97d6-298f7e9cef8e", + "key": "44c87d5e-e8c7-414f-abcc-4f7dbab5448b", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 5.5, @@ -5676,7 +5678,7 @@ }, { "commandType": "dispense", - "key": "b2c2c14c-6874-406a-b9d1-33bc02b7a74f", + "key": "a10a0fa5-b411-4227-b5c0-03bd0f00f1da", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "volume": 5.5, @@ -5691,18 +5693,18 @@ }, { "commandType": "blowout", - "key": "98f8d095-46f4-4349-8c93-21eebfcf05d3", + "key": "d23eab2f-7882-4bed-907e-baf8755ab557", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", "wellName": "A1", - "flowRate": 7, + "flowRate": 1000, "wellLocation": { "origin": "top", "offset": { "z": 0 } } } }, { "commandType": "touchTip", - "key": "d6985dc6-551c-4ceb-bcc9-c833301b1eac", + "key": "916eabaf-7965-4280-b583-043637f47e1c", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "labwareId": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", @@ -5712,7 +5714,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "cdf5e0f0-0598-4e4d-98e8-70a57ff83a4a", + "key": "f03d51ec-9bd4-4a21-b8da-a0ebbffaaac2", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e", "addressableAreaName": "fixedTrash", @@ -5722,12 +5724,12 @@ }, { "commandType": "dropTipInPlace", - "key": "1c0dee1c-97fa-4f33-bb36-9b3b7a2ef73e", + "key": "64a539fe-7de8-4176-9a56-cd0a4201fae9", "params": { "pipetteId": "c6f45030-92a5-11e9-ac62-1b173f839d9e" } }, { "commandType": "waitForDuration", - "key": "d306df0a-3ad2-48ac-9ac2-1151895982e0", + "key": "55faff89-fd16-49ed-ad0b-760f5f359f5e", "params": { "seconds": 3723, "message": "Delay plz" } } ], diff --git a/protocol-designer/fixtures/protocol/8/mix_8_0_0.json b/protocol-designer/fixtures/protocol/8/mix_8_0_0.json index 6ace9e70926..6684720c7d9 100644 --- a/protocol-designer/fixtures/protocol/8/mix_8_0_0.json +++ b/protocol-designer/fixtures/protocol/8/mix_8_0_0.json @@ -6,7 +6,7 @@ "author": "", "description": "A test for 5.0.0 -> 5.1.0 migration", "created": 1600714068238, - "lastModified": 1711742569351, + "lastModified": 1714570500165, "category": null, "subcategory": null, "tags": [] @@ -15,10 +15,10 @@ "name": "opentrons/protocol-designer", "version": "8.1.0", "data": { - "_internalAppBuildDate": "Fri, 29 Mar 2024 20:00:04 GMT", + "_internalAppBuildDate": "Wed, 01 May 2024 13:32:34 GMT", "defaultValues": { "aspirate_mmFromBottom": 1, - "dispense_mmFromBottom": 0.5, + "dispense_mmFromBottom": 1, "touchTip_mmFromTop": -1, "blowout_mmFromTop": 0 }, @@ -58,7 +58,6 @@ "labware": null, "mix_wellOrder_first": "t2b", "mix_wellOrder_second": "l2r", - "blowout_z_offset": 0, "blowout_checkbox": false, "blowout_location": "5ba7047d-d3e2-4845-9eaa-1974af796ead:trashBin", "mix_mmFromBottom": 0.5, @@ -75,9 +74,11 @@ "mix_touchTip_mmFromBottom": null, "dropTip_location": "5ba7047d-d3e2-4845-9eaa-1974af796ead:trashBin", "nozzles": null, - "tipRack": "f1c677c0-fc3a-11ea-8809-e959e7d61d96:opentrons/opentrons_96_tiprack_10ul/1", + "tipRack": "opentrons/opentrons_96_tiprack_10ul/1", "mix_x_position": 0, "mix_y_position": 0, + "blowout_z_offset": 0, + "blowout_flowRate": null, "id": "fc4dc7c0-fc3a-11ea-8809-e959e7d61d96", "stepType": "mix", "stepName": "mix", @@ -2128,7 +2129,7 @@ "commandSchemaId": "opentronsCommandSchemaV8", "commands": [ { - "key": "3004b46c-2b41-4453-8ddc-1629ec3b5249", + "key": "d66aa1db-df76-492d-ab2c-533b982522aa", "commandType": "loadPipette", "params": { "pipetteName": "p20_single_gen2", @@ -2137,7 +2138,7 @@ } }, { - "key": "c318feee-5ec6-40a0-9ecc-554e67b30ce1", + "key": "78921c11-0ed3-49c6-b4c3-08fd71b68917", "commandType": "loadLabware", "params": { "displayName": "Opentrons OT-2 96 Tip Rack 10 µL", @@ -2149,7 +2150,7 @@ } }, { - "key": "3350dee6-aa60-4569-a801-0dfeb5baf8ed", + "key": "f9f07c5b-a0dd-4c3c-8479-15a63ae0642e", "commandType": "loadLabware", "params": { "displayName": "Bio-Rad 96 Well Plate 200 µL PCR", @@ -2162,7 +2163,7 @@ }, { "commandType": "waitForDuration", - "key": "797e70f3-5310-48c2-ba06-12adb92a7b4e", + "key": "72be26a3-bb77-455d-bc32-f100e1a84a0b", "params": { "seconds": 3723, "message": "" } } ], diff --git a/protocol-designer/fixtures/protocol/8/newAdvancedSettingsAndMultiTemp.json b/protocol-designer/fixtures/protocol/8/newAdvancedSettingsAndMultiTemp.json new file mode 100644 index 00000000000..58325488533 --- /dev/null +++ b/protocol-designer/fixtures/protocol/8/newAdvancedSettingsAndMultiTemp.json @@ -0,0 +1,3739 @@ +{ + "$otSharedSchema": "#/protocol/schemas/8", + "schemaVersion": 8, + "metadata": { + "protocolName": "New advanced settings", + "author": "", + "description": "", + "created": 1714565695341, + "lastModified": 1714565808161, + "category": null, + "subcategory": null, + "tags": [] + }, + "designerApplication": { + "name": "opentrons/protocol-designer", + "version": "8.1.0", + "data": { + "_internalAppBuildDate": "Wed, 01 May 2024 12:14:18 GMT", + "defaultValues": { + "aspirate_mmFromBottom": 1, + "dispense_mmFromBottom": 1, + "touchTip_mmFromTop": -1, + "blowout_mmFromTop": 0 + }, + "pipetteTiprackAssignments": { + "21087f15-4c03-4587-8a2b-1ba0b5a501a0": [ + "opentrons/opentrons_flex_96_tiprack_50ul/1" + ] + }, + "dismissedWarnings": { "form": {}, "timeline": {} }, + "ingredients": {}, + "ingredLocations": {}, + "savedStepForms": { + "__INITIAL_DECK_SETUP_STEP__": { + "stepType": "manualIntervention", + "id": "__INITIAL_DECK_SETUP_STEP__", + "labwareLocationUpdate": { + "0d39213c-49c2-4170-bf19-4c09e1b72aca:opentrons/opentrons_flex_96_tiprack_50ul/1": "C2", + "c3c4e3fd-069f-4f3d-9b70-016a20f36de7:opentrons/opentrons_24_aluminumblock_nest_1.5ml_screwcap/1": "b9c56153-9026-42d1-8113-949e15254571:temperatureModuleType", + "32b596f6-79bb-4ad8-a34a-c44620fdb68f:opentrons/opentrons_96_well_aluminum_block/1": "d6966555-6c0e-45e0-8056-428d7c486401:temperatureModuleType", + "c0093e5f-3f7d-4cbf-aa17-d88394108501:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2": "32b596f6-79bb-4ad8-a34a-c44620fdb68f:opentrons/opentrons_96_well_aluminum_block/1" + }, + "pipetteLocationUpdate": { + "21087f15-4c03-4587-8a2b-1ba0b5a501a0": "left" + }, + "moduleLocationUpdate": { + "d6966555-6c0e-45e0-8056-428d7c486401:temperatureModuleType": "D3", + "b9c56153-9026-42d1-8113-949e15254571:temperatureModuleType": "C3" + } + }, + "292e8b18-f59e-4c63-b0f3-e242bf50094b": { + "id": "292e8b18-f59e-4c63-b0f3-e242bf50094b", + "stepType": "moveLiquid", + "stepName": "transfer", + "stepDetails": "", + "pipette": "21087f15-4c03-4587-8a2b-1ba0b5a501a0", + "volume": "10", + "tipRack": "opentrons/opentrons_flex_96_tiprack_50ul/1", + "changeTip": "always", + "path": "single", + "aspirate_wells_grouped": false, + "aspirate_flowRate": null, + "aspirate_labware": "c0093e5f-3f7d-4cbf-aa17-d88394108501:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2", + "aspirate_wells": ["C1"], + "aspirate_wellOrder_first": "t2b", + "aspirate_wellOrder_second": "l2r", + "aspirate_mix_checkbox": false, + "aspirate_mix_times": null, + "aspirate_mix_volume": null, + "aspirate_mmFromBottom": 29, + "aspirate_touchTip_checkbox": false, + "aspirate_touchTip_mmFromBottom": null, + "dispense_flowRate": null, + "dispense_labware": "c3c4e3fd-069f-4f3d-9b70-016a20f36de7:opentrons/opentrons_24_aluminumblock_nest_1.5ml_screwcap/1", + "dispense_wells": ["B3"], + "dispense_wellOrder_first": "t2b", + "dispense_wellOrder_second": "l2r", + "dispense_mix_checkbox": false, + "dispense_mix_times": null, + "dispense_mix_volume": null, + "dispense_mmFromBottom": null, + "dispense_touchTip_checkbox": false, + "dispense_touchTip_mmFromBottom": null, + "disposalVolume_checkbox": true, + "disposalVolume_volume": "1", + "blowout_checkbox": true, + "blowout_location": "source_well", + "preWetTip": false, + "aspirate_airGap_checkbox": false, + "aspirate_airGap_volume": "1", + "aspirate_delay_checkbox": false, + "aspirate_delay_mmFromBottom": null, + "aspirate_delay_seconds": "1", + "dispense_airGap_checkbox": false, + "dispense_airGap_volume": "1", + "dispense_delay_checkbox": false, + "dispense_delay_seconds": "1", + "dispense_delay_mmFromBottom": null, + "dropTip_location": "20ab923c-1290-402e-8476-bba30991f24e:trashBin", + "nozzles": null, + "dispense_x_position": 0, + "dispense_y_position": 0, + "aspirate_x_position": 2, + "aspirate_y_position": -2, + "blowout_z_offset": -12, + "blowout_flowRate": 20 + }, + "960c2d3b-9cf9-49b0-ab4c-af4113f6671a": { + "id": "960c2d3b-9cf9-49b0-ab4c-af4113f6671a", + "stepType": "temperature", + "stepName": "temperature", + "stepDetails": "", + "moduleId": "d6966555-6c0e-45e0-8056-428d7c486401:temperatureModuleType", + "setTemperature": "true", + "targetTemperature": "40" + }, + "5055c5a3-92b7-41e5-935d-e8150e9f4f1c": { + "id": "5055c5a3-92b7-41e5-935d-e8150e9f4f1c", + "stepType": "pause", + "stepName": "pause", + "stepDetails": "", + "pauseAction": "untilTemperature", + "pauseHour": null, + "pauseMinute": null, + "pauseSecond": null, + "pauseMessage": "", + "moduleId": "d6966555-6c0e-45e0-8056-428d7c486401:temperatureModuleType", + "pauseTemperature": "40" + }, + "68a83fc0-726b-4df4-9a14-c43802aa9d0f": { + "id": "68a83fc0-726b-4df4-9a14-c43802aa9d0f", + "stepType": "temperature", + "stepName": "temperature", + "stepDetails": "", + "moduleId": "b9c56153-9026-42d1-8113-949e15254571:temperatureModuleType", + "setTemperature": "true", + "targetTemperature": "4" + }, + "c72b4af9-7488-4109-8221-15a5433f4fd8": { + "id": "c72b4af9-7488-4109-8221-15a5433f4fd8", + "stepType": "pause", + "stepName": "pause", + "stepDetails": "", + "pauseAction": "untilTemperature", + "pauseHour": null, + "pauseMinute": null, + "pauseSecond": null, + "pauseMessage": "", + "moduleId": "b9c56153-9026-42d1-8113-949e15254571:temperatureModuleType", + "pauseTemperature": "4" + }, + "ffb0d1ff-8146-409c-9248-2065a3b27c4d": { + "id": "ffb0d1ff-8146-409c-9248-2065a3b27c4d", + "stepType": "temperature", + "stepName": "temperature", + "stepDetails": "", + "moduleId": "d6966555-6c0e-45e0-8056-428d7c486401:temperatureModuleType", + "setTemperature": "false", + "targetTemperature": null + }, + "eab2ec89-6d11-4246-ae91-d451cb3a5b1d": { + "id": "eab2ec89-6d11-4246-ae91-d451cb3a5b1d", + "stepType": "temperature", + "stepName": "temperature", + "stepDetails": "", + "moduleId": "b9c56153-9026-42d1-8113-949e15254571:temperatureModuleType", + "setTemperature": "false", + "targetTemperature": null + } + }, + "orderedStepIds": [ + "292e8b18-f59e-4c63-b0f3-e242bf50094b", + "960c2d3b-9cf9-49b0-ab4c-af4113f6671a", + "5055c5a3-92b7-41e5-935d-e8150e9f4f1c", + "68a83fc0-726b-4df4-9a14-c43802aa9d0f", + "c72b4af9-7488-4109-8221-15a5433f4fd8", + "ffb0d1ff-8146-409c-9248-2065a3b27c4d", + "eab2ec89-6d11-4246-ae91-d451cb3a5b1d" + ] + } + }, + "robot": { "model": "OT-3 Standard", "deckId": "ot3_standard" }, + "labwareDefinitionSchemaId": "opentronsLabwareSchemaV2", + "labwareDefinitions": { + "opentrons/opentrons_flex_96_tiprack_50ul/1": { + "ordering": [ + ["A1", "B1", "C1", "D1", "E1", "F1", "G1", "H1"], + ["A2", "B2", "C2", "D2", "E2", "F2", "G2", "H2"], + ["A3", "B3", "C3", "D3", "E3", "F3", "G3", "H3"], + ["A4", "B4", "C4", "D4", "E4", "F4", "G4", "H4"], + ["A5", "B5", "C5", "D5", "E5", "F5", "G5", "H5"], + ["A6", "B6", "C6", "D6", "E6", "F6", "G6", "H6"], + ["A7", "B7", "C7", "D7", "E7", "F7", "G7", "H7"], + ["A8", "B8", "C8", "D8", "E8", "F8", "G8", "H8"], + ["A9", "B9", "C9", "D9", "E9", "F9", "G9", "H9"], + ["A10", "B10", "C10", "D10", "E10", "F10", "G10", "H10"], + ["A11", "B11", "C11", "D11", "E11", "F11", "G11", "H11"], + ["A12", "B12", "C12", "D12", "E12", "F12", "G12", "H12"] + ], + "brand": { "brand": "Opentrons", "brandId": [] }, + "metadata": { + "displayName": "Opentrons Flex 96 Tip Rack 50 µL", + "displayCategory": "tipRack", + "displayVolumeUnits": "µL", + "tags": [] + }, + "dimensions": { + "xDimension": 127.75, + "yDimension": 85.75, + "zDimension": 99 + }, + "gripForce": 16, + "gripHeightFromLabwareBottom": 23.9, + "wells": { + "A1": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 14.38, + "y": 74.38, + "z": 1.5 + }, + "B1": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 14.38, + "y": 65.38, + "z": 1.5 + }, + "C1": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 14.38, + "y": 56.38, + "z": 1.5 + }, + "D1": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 14.38, + "y": 47.38, + "z": 1.5 + }, + "E1": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 14.38, + "y": 38.38, + "z": 1.5 + }, + "F1": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 14.38, + "y": 29.38, + "z": 1.5 + }, + "G1": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 14.38, + "y": 20.38, + "z": 1.5 + }, + "H1": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 14.38, + "y": 11.38, + "z": 1.5 + }, + "A2": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 23.38, + "y": 74.38, + "z": 1.5 + }, + "B2": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 23.38, + "y": 65.38, + "z": 1.5 + }, + "C2": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 23.38, + "y": 56.38, + "z": 1.5 + }, + "D2": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 23.38, + "y": 47.38, + "z": 1.5 + }, + "E2": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 23.38, + "y": 38.38, + "z": 1.5 + }, + "F2": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 23.38, + "y": 29.38, + "z": 1.5 + }, + "G2": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 23.38, + "y": 20.38, + "z": 1.5 + }, + "H2": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 23.38, + "y": 11.38, + "z": 1.5 + }, + "A3": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 32.38, + "y": 74.38, + "z": 1.5 + }, + "B3": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 32.38, + "y": 65.38, + "z": 1.5 + }, + "C3": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 32.38, + "y": 56.38, + "z": 1.5 + }, + "D3": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 32.38, + "y": 47.38, + "z": 1.5 + }, + "E3": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 32.38, + "y": 38.38, + "z": 1.5 + }, + "F3": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 32.38, + "y": 29.38, + "z": 1.5 + }, + "G3": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 32.38, + "y": 20.38, + "z": 1.5 + }, + "H3": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 32.38, + "y": 11.38, + "z": 1.5 + }, + "A4": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 41.38, + "y": 74.38, + "z": 1.5 + }, + "B4": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 41.38, + "y": 65.38, + "z": 1.5 + }, + "C4": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 41.38, + "y": 56.38, + "z": 1.5 + }, + "D4": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 41.38, + "y": 47.38, + "z": 1.5 + }, + "E4": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 41.38, + "y": 38.38, + "z": 1.5 + }, + "F4": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 41.38, + "y": 29.38, + "z": 1.5 + }, + "G4": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 41.38, + "y": 20.38, + "z": 1.5 + }, + "H4": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 41.38, + "y": 11.38, + "z": 1.5 + }, + "A5": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 50.38, + "y": 74.38, + "z": 1.5 + }, + "B5": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 50.38, + "y": 65.38, + "z": 1.5 + }, + "C5": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 50.38, + "y": 56.38, + "z": 1.5 + }, + "D5": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 50.38, + "y": 47.38, + "z": 1.5 + }, + "E5": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 50.38, + "y": 38.38, + "z": 1.5 + }, + "F5": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 50.38, + "y": 29.38, + "z": 1.5 + }, + "G5": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 50.38, + "y": 20.38, + "z": 1.5 + }, + "H5": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 50.38, + "y": 11.38, + "z": 1.5 + }, + "A6": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 59.38, + "y": 74.38, + "z": 1.5 + }, + "B6": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 59.38, + "y": 65.38, + "z": 1.5 + }, + "C6": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 59.38, + "y": 56.38, + "z": 1.5 + }, + "D6": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 59.38, + "y": 47.38, + "z": 1.5 + }, + "E6": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 59.38, + "y": 38.38, + "z": 1.5 + }, + "F6": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 59.38, + "y": 29.38, + "z": 1.5 + }, + "G6": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 59.38, + "y": 20.38, + "z": 1.5 + }, + "H6": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 59.38, + "y": 11.38, + "z": 1.5 + }, + "A7": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 68.38, + "y": 74.38, + "z": 1.5 + }, + "B7": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 68.38, + "y": 65.38, + "z": 1.5 + }, + "C7": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 68.38, + "y": 56.38, + "z": 1.5 + }, + "D7": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 68.38, + "y": 47.38, + "z": 1.5 + }, + "E7": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 68.38, + "y": 38.38, + "z": 1.5 + }, + "F7": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 68.38, + "y": 29.38, + "z": 1.5 + }, + "G7": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 68.38, + "y": 20.38, + "z": 1.5 + }, + "H7": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 68.38, + "y": 11.38, + "z": 1.5 + }, + "A8": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 77.38, + "y": 74.38, + "z": 1.5 + }, + "B8": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 77.38, + "y": 65.38, + "z": 1.5 + }, + "C8": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 77.38, + "y": 56.38, + "z": 1.5 + }, + "D8": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 77.38, + "y": 47.38, + "z": 1.5 + }, + "E8": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 77.38, + "y": 38.38, + "z": 1.5 + }, + "F8": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 77.38, + "y": 29.38, + "z": 1.5 + }, + "G8": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 77.38, + "y": 20.38, + "z": 1.5 + }, + "H8": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 77.38, + "y": 11.38, + "z": 1.5 + }, + "A9": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 86.38, + "y": 74.38, + "z": 1.5 + }, + "B9": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 86.38, + "y": 65.38, + "z": 1.5 + }, + "C9": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 86.38, + "y": 56.38, + "z": 1.5 + }, + "D9": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 86.38, + "y": 47.38, + "z": 1.5 + }, + "E9": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 86.38, + "y": 38.38, + "z": 1.5 + }, + "F9": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 86.38, + "y": 29.38, + "z": 1.5 + }, + "G9": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 86.38, + "y": 20.38, + "z": 1.5 + }, + "H9": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 86.38, + "y": 11.38, + "z": 1.5 + }, + "A10": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 95.38, + "y": 74.38, + "z": 1.5 + }, + "B10": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 95.38, + "y": 65.38, + "z": 1.5 + }, + "C10": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 95.38, + "y": 56.38, + "z": 1.5 + }, + "D10": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 95.38, + "y": 47.38, + "z": 1.5 + }, + "E10": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 95.38, + "y": 38.38, + "z": 1.5 + }, + "F10": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 95.38, + "y": 29.38, + "z": 1.5 + }, + "G10": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 95.38, + "y": 20.38, + "z": 1.5 + }, + "H10": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 95.38, + "y": 11.38, + "z": 1.5 + }, + "A11": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 104.38, + "y": 74.38, + "z": 1.5 + }, + "B11": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 104.38, + "y": 65.38, + "z": 1.5 + }, + "C11": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 104.38, + "y": 56.38, + "z": 1.5 + }, + "D11": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 104.38, + "y": 47.38, + "z": 1.5 + }, + "E11": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 104.38, + "y": 38.38, + "z": 1.5 + }, + "F11": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 104.38, + "y": 29.38, + "z": 1.5 + }, + "G11": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 104.38, + "y": 20.38, + "z": 1.5 + }, + "H11": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 104.38, + "y": 11.38, + "z": 1.5 + }, + "A12": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 113.38, + "y": 74.38, + "z": 1.5 + }, + "B12": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 113.38, + "y": 65.38, + "z": 1.5 + }, + "C12": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 113.38, + "y": 56.38, + "z": 1.5 + }, + "D12": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 113.38, + "y": 47.38, + "z": 1.5 + }, + "E12": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 113.38, + "y": 38.38, + "z": 1.5 + }, + "F12": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 113.38, + "y": 29.38, + "z": 1.5 + }, + "G12": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 113.38, + "y": 20.38, + "z": 1.5 + }, + "H12": { + "depth": 97.5, + "shape": "circular", + "diameter": 5.58, + "totalLiquidVolume": 50, + "x": 113.38, + "y": 11.38, + "z": 1.5 + } + }, + "groups": [ + { + "metadata": {}, + "wells": [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1", + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2", + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3", + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4", + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5", + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6", + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7", + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8", + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9", + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10", + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11", + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ] + } + ], + "parameters": { + "format": "96Standard", + "quirks": [], + "isTiprack": true, + "tipLength": 57.9, + "tipOverlap": 10.5, + "isMagneticModuleCompatible": false, + "loadName": "opentrons_flex_96_tiprack_50ul" + }, + "namespace": "opentrons", + "version": 1, + "schemaVersion": 2, + "cornerOffsetFromSlot": { "x": 0, "y": 0, "z": 0 }, + "stackingOffsetWithLabware": { + "opentrons_flex_96_tiprack_adapter": { "x": 0, "y": 0, "z": 121 } + } + }, + "opentrons/opentrons_24_aluminumblock_nest_1.5ml_screwcap/1": { + "ordering": [ + ["A1", "B1", "C1", "D1"], + ["A2", "B2", "C2", "D2"], + ["A3", "B3", "C3", "D3"], + ["A4", "B4", "C4", "D4"], + ["A5", "B5", "C5", "D5"], + ["A6", "B6", "C6", "D6"] + ], + "brand": { + "brand": "Opentrons", + "brandId": [], + "links": ["https://shop.opentrons.com/aluminum-block-set/"] + }, + "metadata": { + "displayName": "Opentrons 24 Well Aluminum Block with NEST 1.5 mL Screwcap", + "displayCategory": "aluminumBlock", + "displayVolumeUnits": "mL", + "tags": [] + }, + "dimensions": { + "xDimension": 127.75, + "yDimension": 85.5, + "zDimension": 49.35 + }, + "wells": { + "A1": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 20.75, + "y": 68.62, + "z": 5.45 + }, + "B1": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 20.75, + "y": 51.37, + "z": 5.45 + }, + "C1": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 20.75, + "y": 34.12, + "z": 5.45 + }, + "D1": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 20.75, + "y": 16.87, + "z": 5.45 + }, + "A2": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 38, + "y": 68.62, + "z": 5.45 + }, + "B2": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 38, + "y": 51.37, + "z": 5.45 + }, + "C2": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 38, + "y": 34.12, + "z": 5.45 + }, + "D2": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 38, + "y": 16.87, + "z": 5.45 + }, + "A3": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 55.25, + "y": 68.62, + "z": 5.45 + }, + "B3": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 55.25, + "y": 51.37, + "z": 5.45 + }, + "C3": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 55.25, + "y": 34.12, + "z": 5.45 + }, + "D3": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 55.25, + "y": 16.87, + "z": 5.45 + }, + "A4": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 72.5, + "y": 68.62, + "z": 5.45 + }, + "B4": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 72.5, + "y": 51.37, + "z": 5.45 + }, + "C4": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 72.5, + "y": 34.12, + "z": 5.45 + }, + "D4": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 72.5, + "y": 16.87, + "z": 5.45 + }, + "A5": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 89.75, + "y": 68.62, + "z": 5.45 + }, + "B5": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 89.75, + "y": 51.37, + "z": 5.45 + }, + "C5": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 89.75, + "y": 34.12, + "z": 5.45 + }, + "D5": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 89.75, + "y": 16.87, + "z": 5.45 + }, + "A6": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 107, + "y": 68.62, + "z": 5.45 + }, + "B6": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 107, + "y": 51.37, + "z": 5.45 + }, + "C6": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 107, + "y": 34.12, + "z": 5.45 + }, + "D6": { + "depth": 43.9, + "shape": "circular", + "diameter": 8.69, + "totalLiquidVolume": 1500, + "x": 107, + "y": 16.87, + "z": 5.45 + } + }, + "groups": [ + { + "metadata": { + "displayName": "NEST 24x1.5 mL Screwcap", + "displayCategory": "tubeRack", + "wellBottomShape": "v" + }, + "brand": { + "brand": "NEST", + "brandId": ["634001"], + "links": ["https://www.nest-biotech.com/sample-vials/59299027.html"] + }, + "wells": [ + "A1", + "B1", + "C1", + "D1", + "A2", + "B2", + "C2", + "D2", + "A3", + "B3", + "C3", + "D3", + "A4", + "B4", + "C4", + "D4", + "A5", + "B5", + "C5", + "D5", + "A6", + "B6", + "C6", + "D6" + ] + } + ], + "parameters": { + "format": "irregular", + "quirks": ["gripperIncompatible"], + "isTiprack": false, + "isMagneticModuleCompatible": false, + "loadName": "opentrons_24_aluminumblock_nest_1.5ml_screwcap" + }, + "namespace": "opentrons", + "version": 1, + "schemaVersion": 2, + "cornerOffsetFromSlot": { "x": 0, "y": 0, "z": 0 } + }, + "opentrons/opentrons_96_well_aluminum_block/1": { + "ordering": [ + ["A1", "B1", "C1", "D1", "E1", "F1", "G1", "H1"], + ["A2", "B2", "C2", "D2", "E2", "F2", "G2", "H2"], + ["A3", "B3", "C3", "D3", "E3", "F3", "G3", "H3"], + ["A4", "B4", "C4", "D4", "E4", "F4", "G4", "H4"], + ["A5", "B5", "C5", "D5", "E5", "F5", "G5", "H5"], + ["A6", "B6", "C6", "D6", "E6", "F6", "G6", "H6"], + ["A7", "B7", "C7", "D7", "E7", "F7", "G7", "H7"], + ["A8", "B8", "C8", "D8", "E8", "F8", "G8", "H8"], + ["A9", "B9", "C9", "D9", "E9", "F9", "G9", "H9"], + ["A10", "B10", "C10", "D10", "E10", "F10", "G10", "H10"], + ["A11", "B11", "C11", "D11", "E11", "F11", "G11", "H11"], + ["A12", "B12", "C12", "D12", "E12", "F12", "G12", "H12"] + ], + "brand": { "brand": "Opentrons", "brandId": [] }, + "metadata": { + "displayName": "Opentrons 96 Well Aluminum Block", + "displayCategory": "adapter", + "displayVolumeUnits": "µL", + "tags": [] + }, + "dimensions": { + "xDimension": 127.76, + "yDimension": 85.48, + "zDimension": 18.16 + }, + "wells": { + "A1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 14.38, + "y": 74.24, + "z": 3.38 + }, + "B1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 14.38, + "y": 65.24, + "z": 3.38 + }, + "C1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 14.38, + "y": 56.24, + "z": 3.38 + }, + "D1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 14.38, + "y": 47.24, + "z": 3.38 + }, + "E1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 14.38, + "y": 38.24, + "z": 3.38 + }, + "F1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 14.38, + "y": 29.24, + "z": 3.38 + }, + "G1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 14.38, + "y": 20.24, + "z": 3.38 + }, + "H1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 14.38, + "y": 11.24, + "z": 3.38 + }, + "A2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 23.38, + "y": 74.24, + "z": 3.38 + }, + "B2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 23.38, + "y": 65.24, + "z": 3.38 + }, + "C2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 23.38, + "y": 56.24, + "z": 3.38 + }, + "D2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 23.38, + "y": 47.24, + "z": 3.38 + }, + "E2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 23.38, + "y": 38.24, + "z": 3.38 + }, + "F2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 23.38, + "y": 29.24, + "z": 3.38 + }, + "G2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 23.38, + "y": 20.24, + "z": 3.38 + }, + "H2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 23.38, + "y": 11.24, + "z": 3.38 + }, + "A3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 32.38, + "y": 74.24, + "z": 3.38 + }, + "B3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 32.38, + "y": 65.24, + "z": 3.38 + }, + "C3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 32.38, + "y": 56.24, + "z": 3.38 + }, + "D3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 32.38, + "y": 47.24, + "z": 3.38 + }, + "E3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 32.38, + "y": 38.24, + "z": 3.38 + }, + "F3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 32.38, + "y": 29.24, + "z": 3.38 + }, + "G3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 32.38, + "y": 20.24, + "z": 3.38 + }, + "H3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 32.38, + "y": 11.24, + "z": 3.38 + }, + "A4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 41.38, + "y": 74.24, + "z": 3.38 + }, + "B4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 41.38, + "y": 65.24, + "z": 3.38 + }, + "C4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 41.38, + "y": 56.24, + "z": 3.38 + }, + "D4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 41.38, + "y": 47.24, + "z": 3.38 + }, + "E4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 41.38, + "y": 38.24, + "z": 3.38 + }, + "F4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 41.38, + "y": 29.24, + "z": 3.38 + }, + "G4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 41.38, + "y": 20.24, + "z": 3.38 + }, + "H4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 41.38, + "y": 11.24, + "z": 3.38 + }, + "A5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 50.38, + "y": 74.24, + "z": 3.38 + }, + "B5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 50.38, + "y": 65.24, + "z": 3.38 + }, + "C5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 50.38, + "y": 56.24, + "z": 3.38 + }, + "D5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 50.38, + "y": 47.24, + "z": 3.38 + }, + "E5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 50.38, + "y": 38.24, + "z": 3.38 + }, + "F5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 50.38, + "y": 29.24, + "z": 3.38 + }, + "G5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 50.38, + "y": 20.24, + "z": 3.38 + }, + "H5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 50.38, + "y": 11.24, + "z": 3.38 + }, + "A6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 59.38, + "y": 74.24, + "z": 3.38 + }, + "B6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 59.38, + "y": 65.24, + "z": 3.38 + }, + "C6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 59.38, + "y": 56.24, + "z": 3.38 + }, + "D6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 59.38, + "y": 47.24, + "z": 3.38 + }, + "E6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 59.38, + "y": 38.24, + "z": 3.38 + }, + "F6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 59.38, + "y": 29.24, + "z": 3.38 + }, + "G6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 59.38, + "y": 20.24, + "z": 3.38 + }, + "H6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 59.38, + "y": 11.24, + "z": 3.38 + }, + "A7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 68.38, + "y": 74.24, + "z": 3.38 + }, + "B7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 68.38, + "y": 65.24, + "z": 3.38 + }, + "C7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 68.38, + "y": 56.24, + "z": 3.38 + }, + "D7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 68.38, + "y": 47.24, + "z": 3.38 + }, + "E7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 68.38, + "y": 38.24, + "z": 3.38 + }, + "F7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 68.38, + "y": 29.24, + "z": 3.38 + }, + "G7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 68.38, + "y": 20.24, + "z": 3.38 + }, + "H7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 68.38, + "y": 11.24, + "z": 3.38 + }, + "A8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 77.38, + "y": 74.24, + "z": 3.38 + }, + "B8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 77.38, + "y": 65.24, + "z": 3.38 + }, + "C8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 77.38, + "y": 56.24, + "z": 3.38 + }, + "D8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 77.38, + "y": 47.24, + "z": 3.38 + }, + "E8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 77.38, + "y": 38.24, + "z": 3.38 + }, + "F8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 77.38, + "y": 29.24, + "z": 3.38 + }, + "G8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 77.38, + "y": 20.24, + "z": 3.38 + }, + "H8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 77.38, + "y": 11.24, + "z": 3.38 + }, + "A9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 86.38, + "y": 74.24, + "z": 3.38 + }, + "B9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 86.38, + "y": 65.24, + "z": 3.38 + }, + "C9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 86.38, + "y": 56.24, + "z": 3.38 + }, + "D9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 86.38, + "y": 47.24, + "z": 3.38 + }, + "E9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 86.38, + "y": 38.24, + "z": 3.38 + }, + "F9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 86.38, + "y": 29.24, + "z": 3.38 + }, + "G9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 86.38, + "y": 20.24, + "z": 3.38 + }, + "H9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 86.38, + "y": 11.24, + "z": 3.38 + }, + "A10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 95.38, + "y": 74.24, + "z": 3.38 + }, + "B10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 95.38, + "y": 65.24, + "z": 3.38 + }, + "C10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 95.38, + "y": 56.24, + "z": 3.38 + }, + "D10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 95.38, + "y": 47.24, + "z": 3.38 + }, + "E10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 95.38, + "y": 38.24, + "z": 3.38 + }, + "F10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 95.38, + "y": 29.24, + "z": 3.38 + }, + "G10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 95.38, + "y": 20.24, + "z": 3.38 + }, + "H10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 95.38, + "y": 11.24, + "z": 3.38 + }, + "A11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 104.38, + "y": 74.24, + "z": 3.38 + }, + "B11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 104.38, + "y": 65.24, + "z": 3.38 + }, + "C11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 104.38, + "y": 56.24, + "z": 3.38 + }, + "D11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 104.38, + "y": 47.24, + "z": 3.38 + }, + "E11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 104.38, + "y": 38.24, + "z": 3.38 + }, + "F11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 104.38, + "y": 29.24, + "z": 3.38 + }, + "G11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 104.38, + "y": 20.24, + "z": 3.38 + }, + "H11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 104.38, + "y": 11.24, + "z": 3.38 + }, + "A12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 113.38, + "y": 74.24, + "z": 3.38 + }, + "B12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 113.38, + "y": 65.24, + "z": 3.38 + }, + "C12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 113.38, + "y": 56.24, + "z": 3.38 + }, + "D12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 113.38, + "y": 47.24, + "z": 3.38 + }, + "E12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 113.38, + "y": 38.24, + "z": 3.38 + }, + "F12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 113.38, + "y": 29.24, + "z": 3.38 + }, + "G12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 113.38, + "y": 20.24, + "z": 3.38 + }, + "H12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 0, + "x": 113.38, + "y": 11.24, + "z": 3.38 + } + }, + "groups": [ + { + "metadata": { "wellBottomShape": "v" }, + "wells": [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1", + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2", + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3", + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4", + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5", + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6", + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7", + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8", + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9", + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10", + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11", + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ] + } + ], + "parameters": { + "format": "96Standard", + "quirks": [], + "isTiprack": false, + "isMagneticModuleCompatible": false, + "loadName": "opentrons_96_well_aluminum_block" + }, + "namespace": "opentrons", + "version": 1, + "schemaVersion": 2, + "allowedRoles": ["adapter"], + "cornerOffsetFromSlot": { "x": 0, "y": 0, "z": 0 }, + "gripperOffsets": { + "default": { + "pickUpOffset": { "x": 0, "y": 0, "z": 0 }, + "dropOffset": { "x": 0, "y": 0, "z": 1 } + } + } + }, + "opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2": { + "ordering": [ + ["A1", "B1", "C1", "D1", "E1", "F1", "G1", "H1"], + ["A2", "B2", "C2", "D2", "E2", "F2", "G2", "H2"], + ["A3", "B3", "C3", "D3", "E3", "F3", "G3", "H3"], + ["A4", "B4", "C4", "D4", "E4", "F4", "G4", "H4"], + ["A5", "B5", "C5", "D5", "E5", "F5", "G5", "H5"], + ["A6", "B6", "C6", "D6", "E6", "F6", "G6", "H6"], + ["A7", "B7", "C7", "D7", "E7", "F7", "G7", "H7"], + ["A8", "B8", "C8", "D8", "E8", "F8", "G8", "H8"], + ["A9", "B9", "C9", "D9", "E9", "F9", "G9", "H9"], + ["A10", "B10", "C10", "D10", "E10", "F10", "G10", "H10"], + ["A11", "B11", "C11", "D11", "E11", "F11", "G11", "H11"], + ["A12", "B12", "C12", "D12", "E12", "F12", "G12", "H12"] + ], + "brand": { + "brand": "NEST", + "brandId": ["402501"], + "links": ["https://www.nest-biotech.com/pcr-plates/58773587.html"] + }, + "metadata": { + "displayName": "NEST 96 Well Plate 100 µL PCR Full Skirt", + "displayCategory": "wellPlate", + "displayVolumeUnits": "µL", + "tags": [] + }, + "dimensions": { + "xDimension": 127.76, + "yDimension": 85.48, + "zDimension": 15.7 + }, + "gripForce": 15, + "gripHeightFromLabwareBottom": 10.65, + "wells": { + "A1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 14.38, + "y": 74.24, + "z": 0.92 + }, + "B1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 14.38, + "y": 65.24, + "z": 0.92 + }, + "C1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 14.38, + "y": 56.24, + "z": 0.92 + }, + "D1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 14.38, + "y": 47.24, + "z": 0.92 + }, + "E1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 14.38, + "y": 38.24, + "z": 0.92 + }, + "F1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 14.38, + "y": 29.24, + "z": 0.92 + }, + "G1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 14.38, + "y": 20.24, + "z": 0.92 + }, + "H1": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 14.38, + "y": 11.24, + "z": 0.92 + }, + "A2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 23.38, + "y": 74.24, + "z": 0.92 + }, + "B2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 23.38, + "y": 65.24, + "z": 0.92 + }, + "C2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 23.38, + "y": 56.24, + "z": 0.92 + }, + "D2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 23.38, + "y": 47.24, + "z": 0.92 + }, + "E2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 23.38, + "y": 38.24, + "z": 0.92 + }, + "F2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 23.38, + "y": 29.24, + "z": 0.92 + }, + "G2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 23.38, + "y": 20.24, + "z": 0.92 + }, + "H2": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 23.38, + "y": 11.24, + "z": 0.92 + }, + "A3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 32.38, + "y": 74.24, + "z": 0.92 + }, + "B3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 32.38, + "y": 65.24, + "z": 0.92 + }, + "C3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 32.38, + "y": 56.24, + "z": 0.92 + }, + "D3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 32.38, + "y": 47.24, + "z": 0.92 + }, + "E3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 32.38, + "y": 38.24, + "z": 0.92 + }, + "F3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 32.38, + "y": 29.24, + "z": 0.92 + }, + "G3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 32.38, + "y": 20.24, + "z": 0.92 + }, + "H3": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 32.38, + "y": 11.24, + "z": 0.92 + }, + "A4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 41.38, + "y": 74.24, + "z": 0.92 + }, + "B4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 41.38, + "y": 65.24, + "z": 0.92 + }, + "C4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 41.38, + "y": 56.24, + "z": 0.92 + }, + "D4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 41.38, + "y": 47.24, + "z": 0.92 + }, + "E4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 41.38, + "y": 38.24, + "z": 0.92 + }, + "F4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 41.38, + "y": 29.24, + "z": 0.92 + }, + "G4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 41.38, + "y": 20.24, + "z": 0.92 + }, + "H4": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 41.38, + "y": 11.24, + "z": 0.92 + }, + "A5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 50.38, + "y": 74.24, + "z": 0.92 + }, + "B5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 50.38, + "y": 65.24, + "z": 0.92 + }, + "C5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 50.38, + "y": 56.24, + "z": 0.92 + }, + "D5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 50.38, + "y": 47.24, + "z": 0.92 + }, + "E5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 50.38, + "y": 38.24, + "z": 0.92 + }, + "F5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 50.38, + "y": 29.24, + "z": 0.92 + }, + "G5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 50.38, + "y": 20.24, + "z": 0.92 + }, + "H5": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 50.38, + "y": 11.24, + "z": 0.92 + }, + "A6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 59.38, + "y": 74.24, + "z": 0.92 + }, + "B6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 59.38, + "y": 65.24, + "z": 0.92 + }, + "C6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 59.38, + "y": 56.24, + "z": 0.92 + }, + "D6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 59.38, + "y": 47.24, + "z": 0.92 + }, + "E6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 59.38, + "y": 38.24, + "z": 0.92 + }, + "F6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 59.38, + "y": 29.24, + "z": 0.92 + }, + "G6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 59.38, + "y": 20.24, + "z": 0.92 + }, + "H6": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 59.38, + "y": 11.24, + "z": 0.92 + }, + "A7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 68.38, + "y": 74.24, + "z": 0.92 + }, + "B7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 68.38, + "y": 65.24, + "z": 0.92 + }, + "C7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 68.38, + "y": 56.24, + "z": 0.92 + }, + "D7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 68.38, + "y": 47.24, + "z": 0.92 + }, + "E7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 68.38, + "y": 38.24, + "z": 0.92 + }, + "F7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 68.38, + "y": 29.24, + "z": 0.92 + }, + "G7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 68.38, + "y": 20.24, + "z": 0.92 + }, + "H7": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 68.38, + "y": 11.24, + "z": 0.92 + }, + "A8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 77.38, + "y": 74.24, + "z": 0.92 + }, + "B8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 77.38, + "y": 65.24, + "z": 0.92 + }, + "C8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 77.38, + "y": 56.24, + "z": 0.92 + }, + "D8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 77.38, + "y": 47.24, + "z": 0.92 + }, + "E8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 77.38, + "y": 38.24, + "z": 0.92 + }, + "F8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 77.38, + "y": 29.24, + "z": 0.92 + }, + "G8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 77.38, + "y": 20.24, + "z": 0.92 + }, + "H8": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 77.38, + "y": 11.24, + "z": 0.92 + }, + "A9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 86.38, + "y": 74.24, + "z": 0.92 + }, + "B9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 86.38, + "y": 65.24, + "z": 0.92 + }, + "C9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 86.38, + "y": 56.24, + "z": 0.92 + }, + "D9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 86.38, + "y": 47.24, + "z": 0.92 + }, + "E9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 86.38, + "y": 38.24, + "z": 0.92 + }, + "F9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 86.38, + "y": 29.24, + "z": 0.92 + }, + "G9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 86.38, + "y": 20.24, + "z": 0.92 + }, + "H9": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 86.38, + "y": 11.24, + "z": 0.92 + }, + "A10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 95.38, + "y": 74.24, + "z": 0.92 + }, + "B10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 95.38, + "y": 65.24, + "z": 0.92 + }, + "C10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 95.38, + "y": 56.24, + "z": 0.92 + }, + "D10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 95.38, + "y": 47.24, + "z": 0.92 + }, + "E10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 95.38, + "y": 38.24, + "z": 0.92 + }, + "F10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 95.38, + "y": 29.24, + "z": 0.92 + }, + "G10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 95.38, + "y": 20.24, + "z": 0.92 + }, + "H10": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 95.38, + "y": 11.24, + "z": 0.92 + }, + "A11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 104.38, + "y": 74.24, + "z": 0.92 + }, + "B11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 104.38, + "y": 65.24, + "z": 0.92 + }, + "C11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 104.38, + "y": 56.24, + "z": 0.92 + }, + "D11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 104.38, + "y": 47.24, + "z": 0.92 + }, + "E11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 104.38, + "y": 38.24, + "z": 0.92 + }, + "F11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 104.38, + "y": 29.24, + "z": 0.92 + }, + "G11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 104.38, + "y": 20.24, + "z": 0.92 + }, + "H11": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 104.38, + "y": 11.24, + "z": 0.92 + }, + "A12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 113.38, + "y": 74.24, + "z": 0.92 + }, + "B12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 113.38, + "y": 65.24, + "z": 0.92 + }, + "C12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 113.38, + "y": 56.24, + "z": 0.92 + }, + "D12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 113.38, + "y": 47.24, + "z": 0.92 + }, + "E12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 113.38, + "y": 38.24, + "z": 0.92 + }, + "F12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 113.38, + "y": 29.24, + "z": 0.92 + }, + "G12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 113.38, + "y": 20.24, + "z": 0.92 + }, + "H12": { + "depth": 14.78, + "shape": "circular", + "diameter": 5.34, + "totalLiquidVolume": 100, + "x": 113.38, + "y": 11.24, + "z": 0.92 + } + }, + "groups": [ + { + "metadata": { "wellBottomShape": "v" }, + "wells": [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1", + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2", + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3", + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4", + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5", + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6", + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7", + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8", + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9", + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10", + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11", + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ] + } + ], + "parameters": { + "format": "96Standard", + "isTiprack": false, + "isMagneticModuleCompatible": true, + "magneticModuleEngageHeight": 20, + "loadName": "nest_96_wellplate_100ul_pcr_full_skirt" + }, + "namespace": "opentrons", + "version": 2, + "schemaVersion": 2, + "cornerOffsetFromSlot": { "x": 0, "y": 0, "z": 0 }, + "stackingOffsetWithLabware": { + "opentrons_96_pcr_adapter": { "x": 0, "y": 0, "z": 10.2 }, + "opentrons_96_well_aluminum_block": { "x": 0, "y": 0, "z": 12.66 } + }, + "stackingOffsetWithModule": { + "thermocyclerModuleV2": { "x": 0, "y": 0, "z": 10.8 } + } + } + }, + "liquidSchemaId": "opentronsLiquidSchemaV1", + "liquids": {}, + "commandSchemaId": "opentronsCommandSchemaV8", + "commands": [ + { + "key": "dd8e7395-4f5d-47da-932c-581e6b330102", + "commandType": "loadPipette", + "params": { + "pipetteName": "p50_single_flex", + "mount": "left", + "pipetteId": "21087f15-4c03-4587-8a2b-1ba0b5a501a0" + } + }, + { + "key": "069341d0-374a-457f-811a-beb25f824ceb", + "commandType": "loadModule", + "params": { + "model": "temperatureModuleV2", + "location": { "slotName": "D3" }, + "moduleId": "d6966555-6c0e-45e0-8056-428d7c486401:temperatureModuleType" + } + }, + { + "key": "f2dbc8cc-b373-4043-b9f3-68f5eae4d69d", + "commandType": "loadModule", + "params": { + "model": "temperatureModuleV2", + "location": { "slotName": "C3" }, + "moduleId": "b9c56153-9026-42d1-8113-949e15254571:temperatureModuleType" + } + }, + { + "key": "f425f1d1-02c9-488b-865b-13f95497c9e8", + "commandType": "loadLabware", + "params": { + "displayName": "Opentrons 96 Well Aluminum Block", + "labwareId": "32b596f6-79bb-4ad8-a34a-c44620fdb68f:opentrons/opentrons_96_well_aluminum_block/1", + "loadName": "opentrons_96_well_aluminum_block", + "namespace": "opentrons", + "version": 1, + "location": { + "moduleId": "d6966555-6c0e-45e0-8056-428d7c486401:temperatureModuleType" + } + } + }, + { + "key": "ecc436f2-34ab-42bc-9dcd-12cbcd00a835", + "commandType": "loadLabware", + "params": { + "displayName": "Opentrons Flex 96 Tip Rack 50 µL", + "labwareId": "0d39213c-49c2-4170-bf19-4c09e1b72aca:opentrons/opentrons_flex_96_tiprack_50ul/1", + "loadName": "opentrons_flex_96_tiprack_50ul", + "namespace": "opentrons", + "version": 1, + "location": { "slotName": "C2" } + } + }, + { + "key": "212e0de6-00dc-460b-ac07-cd6a12fbc04f", + "commandType": "loadLabware", + "params": { + "displayName": "Opentrons 24 Well Aluminum Block with NEST 1.5 mL Screwcap", + "labwareId": "c3c4e3fd-069f-4f3d-9b70-016a20f36de7:opentrons/opentrons_24_aluminumblock_nest_1.5ml_screwcap/1", + "loadName": "opentrons_24_aluminumblock_nest_1.5ml_screwcap", + "namespace": "opentrons", + "version": 1, + "location": { + "moduleId": "b9c56153-9026-42d1-8113-949e15254571:temperatureModuleType" + } + } + }, + { + "key": "a8b0443f-afad-4e59-91a7-5b61f7e6836e", + "commandType": "loadLabware", + "params": { + "displayName": "NEST 96 Well Plate 100 µL PCR Full Skirt", + "labwareId": "c0093e5f-3f7d-4cbf-aa17-d88394108501:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2", + "loadName": "nest_96_wellplate_100ul_pcr_full_skirt", + "namespace": "opentrons", + "version": 2, + "location": { + "labwareId": "32b596f6-79bb-4ad8-a34a-c44620fdb68f:opentrons/opentrons_96_well_aluminum_block/1" + } + } + }, + { + "commandType": "pickUpTip", + "key": "ae442c49-0f55-4982-9796-91213f5c51f9", + "params": { + "pipetteId": "21087f15-4c03-4587-8a2b-1ba0b5a501a0", + "labwareId": "0d39213c-49c2-4170-bf19-4c09e1b72aca:opentrons/opentrons_flex_96_tiprack_50ul/1", + "wellName": "A1" + } + }, + { + "commandType": "configureForVolume", + "key": "1d992cbb-79cc-426e-9b4a-29768a75f092", + "params": { + "pipetteId": "21087f15-4c03-4587-8a2b-1ba0b5a501a0", + "volume": 10 + } + }, + { + "commandType": "aspirate", + "key": "5e59176d-a8e7-4c39-9337-053a2d6e02db", + "params": { + "pipetteId": "21087f15-4c03-4587-8a2b-1ba0b5a501a0", + "volume": 10, + "labwareId": "c0093e5f-3f7d-4cbf-aa17-d88394108501:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2", + "wellName": "C1", + "wellLocation": { + "origin": "bottom", + "offset": { "z": 29, "x": 2, "y": -2 } + }, + "flowRate": 35 + } + }, + { + "commandType": "dispense", + "key": "4e9f4b46-e095-40e2-95c8-abed29538675", + "params": { + "pipetteId": "21087f15-4c03-4587-8a2b-1ba0b5a501a0", + "volume": 10, + "labwareId": "c3c4e3fd-069f-4f3d-9b70-016a20f36de7:opentrons/opentrons_24_aluminumblock_nest_1.5ml_screwcap/1", + "wellName": "B3", + "wellLocation": { + "origin": "bottom", + "offset": { "z": 1, "x": 0, "y": 0 } + }, + "flowRate": 57 + } + }, + { + "commandType": "blowout", + "key": "5ae1dc28-2095-453a-88e4-2e6dd50e5c4d", + "params": { + "pipetteId": "21087f15-4c03-4587-8a2b-1ba0b5a501a0", + "labwareId": "c0093e5f-3f7d-4cbf-aa17-d88394108501:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2", + "wellName": "C1", + "flowRate": 20, + "wellLocation": { "origin": "top", "offset": { "z": -12 } } + } + }, + { + "commandType": "moveToAddressableAreaForDropTip", + "key": "7786878c-2a71-41b6-9971-14ea88c3bf9d", + "params": { + "pipetteId": "21087f15-4c03-4587-8a2b-1ba0b5a501a0", + "addressableAreaName": "movableTrashA3", + "offset": { "x": 0, "y": 0, "z": 0 }, + "alternateDropLocation": true + } + }, + { + "commandType": "dropTipInPlace", + "key": "77da638e-5609-40a6-be69-1309b7ae9eb6", + "params": { "pipetteId": "21087f15-4c03-4587-8a2b-1ba0b5a501a0" } + }, + { + "commandType": "temperatureModule/setTargetTemperature", + "key": "8eedd2c4-7474-4246-a896-f93040722a01", + "params": { + "moduleId": "d6966555-6c0e-45e0-8056-428d7c486401:temperatureModuleType", + "celsius": 40 + } + }, + { + "commandType": "temperatureModule/waitForTemperature", + "key": "a4cad3c5-b771-4278-8776-5b5417ac659e", + "params": { + "moduleId": "d6966555-6c0e-45e0-8056-428d7c486401:temperatureModuleType", + "celsius": 40 + } + }, + { + "commandType": "temperatureModule/setTargetTemperature", + "key": "9849f4ff-8723-4851-a637-3d311d9af210", + "params": { + "moduleId": "b9c56153-9026-42d1-8113-949e15254571:temperatureModuleType", + "celsius": 4 + } + }, + { + "commandType": "temperatureModule/waitForTemperature", + "key": "d3c30460-b6a7-4834-8c86-f1f3302e670f", + "params": { + "moduleId": "b9c56153-9026-42d1-8113-949e15254571:temperatureModuleType", + "celsius": 4 + } + }, + { + "commandType": "temperatureModule/deactivate", + "key": "82b767e6-0bfb-4175-8780-e48fbbc8f35c", + "params": { + "moduleId": "d6966555-6c0e-45e0-8056-428d7c486401:temperatureModuleType" + } + }, + { + "commandType": "temperatureModule/deactivate", + "key": "60f2762f-a1ef-40cc-a729-95cf514640ea", + "params": { + "moduleId": "b9c56153-9026-42d1-8113-949e15254571:temperatureModuleType" + } + } + ], + "commandAnnotationSchemaId": "opentronsCommandAnnotationSchemaV1", + "commandAnnotations": [] +} diff --git a/protocol-designer/fixtures/protocol/8/ninetySixChannelFullAndColumn.json b/protocol-designer/fixtures/protocol/8/ninetySixChannelFullAndColumn.json index 702945f0b8c..dc58d3219a2 100644 --- a/protocol-designer/fixtures/protocol/8/ninetySixChannelFullAndColumn.json +++ b/protocol-designer/fixtures/protocol/8/ninetySixChannelFullAndColumn.json @@ -6,7 +6,7 @@ "author": "", "description": "", "created": 1701805621086, - "lastModified": 1711742604736, + "lastModified": 1714570523087, "category": null, "subcategory": null, "tags": [] @@ -15,10 +15,10 @@ "name": "opentrons/protocol-designer", "version": "8.1.0", "data": { - "_internalAppBuildDate": "Fri, 29 Mar 2024 20:00:04 GMT", + "_internalAppBuildDate": "Wed, 01 May 2024 13:32:34 GMT", "defaultValues": { "aspirate_mmFromBottom": 1, - "dispense_mmFromBottom": 0.5, + "dispense_mmFromBottom": 1, "touchTip_mmFromTop": -1, "blowout_mmFromTop": 0 }, @@ -50,7 +50,7 @@ "83a095fa-b649-4105-99d4-177f1a3f363a": { "pipette": "de7da440-95ec-43e8-8723-851321fbd6f9", "volume": "10", - "tipRack": "75aa666f-98d8-4af9-908e-963ced428580:opentrons/opentrons_flex_96_tiprack_50ul/1", + "tipRack": "opentrons/opentrons_flex_96_tiprack_50ul/1", "changeTip": "always", "path": "single", "aspirate_wells_grouped": false, @@ -78,7 +78,6 @@ "dispense_touchTip_mmFromBottom": null, "disposalVolume_checkbox": true, "disposalVolume_volume": "5", - "blowout_z_offset": 0, "blowout_checkbox": false, "blowout_location": null, "preWetTip": false, @@ -98,6 +97,8 @@ "dispense_y_position": 0, "aspirate_x_position": 0, "aspirate_y_position": 0, + "blowout_z_offset": 0, + "blowout_flowRate": null, "id": "83a095fa-b649-4105-99d4-177f1a3f363a", "stepType": "moveLiquid", "stepName": "transfer", @@ -106,7 +107,7 @@ "f5ea3139-1585-4848-9d5f-832eb88c99ca": { "pipette": "de7da440-95ec-43e8-8723-851321fbd6f9", "volume": "10", - "tipRack": "75aa666f-98d8-4af9-908e-963ced428580:opentrons/opentrons_flex_96_tiprack_50ul/1", + "tipRack": "opentrons/opentrons_flex_96_tiprack_50ul/1", "changeTip": "always", "path": "single", "aspirate_wells_grouped": false, @@ -134,7 +135,6 @@ "dispense_touchTip_mmFromBottom": null, "disposalVolume_checkbox": true, "disposalVolume_volume": "5", - "blowout_z_offset": 0, "blowout_checkbox": false, "blowout_location": null, "preWetTip": false, @@ -154,6 +154,8 @@ "dispense_y_position": 0, "aspirate_x_position": 0, "aspirate_y_position": 0, + "blowout_z_offset": 0, + "blowout_flowRate": null, "id": "f5ea3139-1585-4848-9d5f-832eb88c99ca", "stepType": "moveLiquid", "stepName": "transfer", @@ -2243,7 +2245,7 @@ "commandSchemaId": "opentronsCommandSchemaV8", "commands": [ { - "key": "7224d1a7-a7b3-4bb3-bc5c-65aa98565616", + "key": "1370b9a4-1e65-4203-9106-896db3db3bd3", "commandType": "loadPipette", "params": { "pipetteName": "p1000_96", @@ -2252,7 +2254,7 @@ } }, { - "key": "dcddeb3c-66d9-4868-9f9f-fbd47d754fc4", + "key": "d65a7183-875a-443a-b26a-6a2470291dce", "commandType": "loadLabware", "params": { "displayName": "Opentrons Flex 96 Tip Rack Adapter", @@ -2264,7 +2266,7 @@ } }, { - "key": "c206434e-aa1e-44ee-8667-29accd89941a", + "key": "d05d92c6-d0d1-4886-aaef-c180b6953763", "commandType": "loadLabware", "params": { "displayName": "Opentrons Flex 96 Tip Rack 50 µL", @@ -2278,7 +2280,7 @@ } }, { - "key": "3cdba839-f0fa-4e50-8399-94338cced032", + "key": "bb161828-5fd9-4d84-8209-c1f5de48ba99", "commandType": "loadLabware", "params": { "displayName": "Bio-Rad 96 Well Plate 200 µL PCR", @@ -2290,7 +2292,7 @@ } }, { - "key": "7f75bf03-3036-4847-afbf-4bbefdf6cee8", + "key": "8821778d-8456-4c74-8e29-da7604c012ec", "commandType": "loadLabware", "params": { "displayName": "Opentrons Flex 96 Tip Rack 50 µL", @@ -2303,7 +2305,7 @@ }, { "commandType": "configureNozzleLayout", - "key": "2326c781-0416-4319-b954-16929077b5e3", + "key": "a2a88d61-5c01-45bf-bcb8-91c893328b53", "params": { "pipetteId": "de7da440-95ec-43e8-8723-851321fbd6f9", "configurationParams": { "style": "ALL" } @@ -2311,7 +2313,7 @@ }, { "commandType": "pickUpTip", - "key": "86f7ac25-739d-4a38-8bf4-4730a8e6cce7", + "key": "747ca334-8955-4069-8473-351be7666ee0", "params": { "pipetteId": "de7da440-95ec-43e8-8723-851321fbd6f9", "labwareId": "75aa666f-98d8-4af9-908e-963ced428580:opentrons/opentrons_flex_96_tiprack_50ul/1", @@ -2320,7 +2322,7 @@ }, { "commandType": "aspirate", - "key": "0113e27d-0949-4305-8f0b-5467753dfac3", + "key": "b1ffc410-ed41-4c83-bebd-145ae0ca05d8", "params": { "pipetteId": "de7da440-95ec-43e8-8723-851321fbd6f9", "volume": 10, @@ -2335,7 +2337,7 @@ }, { "commandType": "moveToAddressableArea", - "key": "79c134c0-5042-4243-8a81-95ad54594ab3", + "key": "9100f4e2-b808-43d3-8c72-355dcce98b33", "params": { "pipetteId": "de7da440-95ec-43e8-8723-851321fbd6f9", "addressableAreaName": "movableTrashA3", @@ -2344,7 +2346,7 @@ }, { "commandType": "dispenseInPlace", - "key": "2ce5b534-62b3-4415-bdd6-747fb57545be", + "key": "4088260b-f0e9-4d3a-852c-13b7d467cc2d", "params": { "pipetteId": "de7da440-95ec-43e8-8723-851321fbd6f9", "volume": 10, @@ -2353,7 +2355,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "7212407e-0bd1-4ef5-a8c7-4c6f95cee357", + "key": "8169cddb-5337-4bcf-bbfb-eb6307764b90", "params": { "pipetteId": "de7da440-95ec-43e8-8723-851321fbd6f9", "addressableAreaName": "movableTrashA3", @@ -2363,12 +2365,12 @@ }, { "commandType": "dropTipInPlace", - "key": "55286f40-e2c1-44f6-a3f3-032bfbf89f3d", + "key": "e0db70c1-546f-44ce-91c7-b18c37fcbcef", "params": { "pipetteId": "de7da440-95ec-43e8-8723-851321fbd6f9" } }, { "commandType": "configureNozzleLayout", - "key": "47ab8f5c-a2dc-40e0-a6db-3c2ff6c48778", + "key": "97fb0aee-ce45-427f-b3af-b9b9a1923778", "params": { "pipetteId": "de7da440-95ec-43e8-8723-851321fbd6f9", "configurationParams": { "primaryNozzle": "A12", "style": "COLUMN" } @@ -2376,7 +2378,7 @@ }, { "commandType": "pickUpTip", - "key": "c6f563fd-4f3f-4bd8-833e-3519c4fb0026", + "key": "203d9332-ea93-4047-97e8-58516d18373b", "params": { "pipetteId": "de7da440-95ec-43e8-8723-851321fbd6f9", "labwareId": "9bd16b50-4ae9-4cfd-8583-3378087e6a6c:opentrons/opentrons_flex_96_tiprack_50ul/1", @@ -2385,7 +2387,7 @@ }, { "commandType": "aspirate", - "key": "ee919504-5c21-40c5-9205-00e8aee06718", + "key": "3b5ef144-b0a9-4136-8579-3ddef13d60d1", "params": { "pipetteId": "de7da440-95ec-43e8-8723-851321fbd6f9", "volume": 10, @@ -2400,7 +2402,7 @@ }, { "commandType": "moveToAddressableArea", - "key": "6c1dbdec-0d3a-4693-810b-b28984382fce", + "key": "b1b0cb96-cf8a-4c19-ad8b-7a515b720c80", "params": { "pipetteId": "de7da440-95ec-43e8-8723-851321fbd6f9", "addressableAreaName": "movableTrashA3", @@ -2409,7 +2411,7 @@ }, { "commandType": "dispenseInPlace", - "key": "d7ad2bf5-3033-4168-adf4-082306dc5467", + "key": "b49b05e6-f82a-4dd3-9288-8f5eba004b2a", "params": { "pipetteId": "de7da440-95ec-43e8-8723-851321fbd6f9", "volume": 10, @@ -2418,7 +2420,7 @@ }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "9ca4968e-0995-4354-95a1-37964599784f", + "key": "6e0104da-5608-490a-ae14-e67db91331fe", "params": { "pipetteId": "de7da440-95ec-43e8-8723-851321fbd6f9", "addressableAreaName": "movableTrashA3", @@ -2428,7 +2430,7 @@ }, { "commandType": "dropTipInPlace", - "key": "548bbf90-da13-4487-a878-dd363b17d906", + "key": "a1266ec5-4602-43e7-a5e5-6512e7560eb9", "params": { "pipetteId": "de7da440-95ec-43e8-8723-851321fbd6f9" } } ], diff --git a/protocol-designer/src/components/ColorPicker/index.tsx b/protocol-designer/src/components/ColorPicker/index.tsx index 65fb33d1980..676eae59397 100644 --- a/protocol-designer/src/components/ColorPicker/index.tsx +++ b/protocol-designer/src/components/ColorPicker/index.tsx @@ -11,6 +11,7 @@ interface ColorPickerProps { } export function ColorPicker(props: ColorPickerProps): JSX.Element { + const { value, onChange } = props const [showColorPicker, setShowColorPicker] = React.useState(false) return ( @@ -27,7 +28,7 @@ export function ColorPicker(props: ColorPickerProps): JSX.Element {
@@ -39,9 +40,9 @@ export function ColorPicker(props: ColorPickerProps): JSX.Element { /> { - props.onChange(color.hex) + onChange(color.hex) }} />
diff --git a/protocol-designer/src/components/EditModules.tsx b/protocol-designer/src/components/EditModules.tsx index 9df9defbdd9..b3d62ac1c70 100644 --- a/protocol-designer/src/components/EditModules.tsx +++ b/protocol-designer/src/components/EditModules.tsx @@ -1,14 +1,20 @@ import * as React from 'react' import { useSelector, useDispatch } from 'react-redux' +import { + FLEX_ROBOT_TYPE, + TEMPERATURE_MODULE_TYPE, +} from '@opentrons/shared-data' import { selectors as stepFormSelectors, actions as stepFormActions, } from '../step-forms' import { moveDeckItem } from '../labware-ingred/actions/actions' +import { getRobotType } from '../file-data/selectors' +import { EditMultipleModulesModal } from './modals/EditModulesModal/EditMultipleModulesModal' import { useBlockingHint } from './Hints/useBlockingHint' import { MagneticModuleWarningModalContent } from './modals/EditModulesModal/MagneticModuleWarningModalContent' import { EditModulesModal } from './modals/EditModulesModal' -import { ModuleModel, ModuleType } from '@opentrons/shared-data' +import type { ModuleModel, ModuleType } from '@opentrons/shared-data' export interface EditModulesProps { moduleToEdit: { @@ -27,6 +33,9 @@ export const EditModules = (props: EditModulesProps): JSX.Element => { const { onCloseClick, moduleToEdit } = props const { moduleId, moduleType } = moduleToEdit const _initialDeckSetup = useSelector(stepFormSelectors.getInitialDeckSetup) + const robotType = useSelector(getRobotType) + const showMultipleModuleModal = + robotType === FLEX_ROBOT_TYPE && moduleType === TEMPERATURE_MODULE_TYPE const moduleOnDeck = moduleId ? _initialDeckSetup.modules[moduleId] : null const [ @@ -74,16 +83,24 @@ export const EditModules = (props: EditModulesProps): JSX.Element => { enabled: changeModuleWarningInfo !== null, }) - return ( - changeModuleWarning ?? ( - + ) + if (showMultipleModuleModal) { + modal = ( + ) - ) + } + return changeModuleWarning ?? modal } diff --git a/protocol-designer/src/components/FileSidebar/FileSidebar.tsx b/protocol-designer/src/components/FileSidebar/FileSidebar.tsx index e05a80e3163..11b8d21053d 100644 --- a/protocol-designer/src/components/FileSidebar/FileSidebar.tsx +++ b/protocol-designer/src/components/FileSidebar/FileSidebar.tsx @@ -237,9 +237,9 @@ export function v8WarningContent(t: any): JSX.Element { return (

- {t(`hint.export_v8_protocol_7_1.body1`)}{' '} - {t(`hint.export_v8_protocol_7_1.body2`)} - {t(`hint.export_v8_protocol_7_1.body3`)} + {t(`hint.export_v8_1_protocol_7_3.body1`)}{' '} + {t(`hint.export_v8_1_protocol_7_3.body2`)} + {t(`hint.export_v8_1_protocol_7_3.body3`)}

) @@ -350,7 +350,7 @@ export function FileSidebar(): JSX.Element { content: React.ReactNode } => { return { - hintKey: 'export_v8_protocol_7_1', + hintKey: 'export_v8_1_protocol_7_3', content: v8WarningContent(t), } } diff --git a/protocol-designer/src/components/FileSidebar/__tests__/FileSidebar.test.tsx b/protocol-designer/src/components/FileSidebar/__tests__/FileSidebar.test.tsx index a9d2978b981..827af5a2aa8 100644 --- a/protocol-designer/src/components/FileSidebar/__tests__/FileSidebar.test.tsx +++ b/protocol-designer/src/components/FileSidebar/__tests__/FileSidebar.test.tsx @@ -74,6 +74,13 @@ describe('FileSidebar', () => { vi.resetAllMocks() cleanup() }) + it('renders the file sidebar and exports with blocking hint for exporting', () => { + vi.mocked(useBlockingHint).mockReturnValue(
mock blocking hint
) + render() + fireEvent.click(screen.getByRole('button', { name: 'Export' })) + expect(vi.mocked(useBlockingHint)).toHaveBeenCalled() + screen.getByText('mock blocking hint') + }) it('renders the file sidebar and buttons work as expected with no warning upon export', () => { render() screen.getByText('Protocol File') diff --git a/protocol-designer/src/components/LabwareSelectionModal/LabwareSelectionModal.tsx b/protocol-designer/src/components/LabwareSelectionModal/LabwareSelectionModal.tsx index f0958eb1364..58da8b83dbc 100644 --- a/protocol-designer/src/components/LabwareSelectionModal/LabwareSelectionModal.tsx +++ b/protocol-designer/src/components/LabwareSelectionModal/LabwareSelectionModal.tsx @@ -470,7 +470,7 @@ export function LabwareSelectionModal(): JSX.Element | null {
    {customLabwareURIs.length > 0 ? ( { }) render() fireEvent.click( - screen.getByText(nestedTextMatcher('adapter compatible labware')) + screen.getByText(nestedTextMatcher('Adapter Compatible Labware')) ) screen.getByText('Opentrons GEB 1000uL Tiprack') }) diff --git a/protocol-designer/src/components/LiquidsPage/LiquidEditForm.tsx b/protocol-designer/src/components/LiquidsPage/LiquidEditForm.tsx index 887e1ac8f64..13a01dcb314 100644 --- a/protocol-designer/src/components/LiquidsPage/LiquidEditForm.tsx +++ b/protocol-designer/src/components/LiquidsPage/LiquidEditForm.tsx @@ -4,7 +4,6 @@ import { Controller, useForm } from 'react-hook-form' import { yupResolver } from '@hookform/resolvers/yup' import { useSelector } from 'react-redux' import * as Yup from 'yup' -import { swatchColors } from '../swatchColors' import { Card, DeprecatedCheckboxField, @@ -18,18 +17,23 @@ import { } from '@opentrons/components' import { DEPRECATED_WHALE_GREY } from '@opentrons/shared-data' import { selectors } from '../../labware-ingred/selectors' +import { swatchColors } from '../swatchColors' +import { ColorPicker } from '../ColorPicker' import styles from './LiquidEditForm.module.css' import formStyles from '../forms/forms.module.css' -import { LiquidGroup } from '../../labware-ingred/types' -import { ColorPicker } from '../ColorPicker' -import { ColorResult } from 'react-color' +import type { ColorResult } from 'react-color' +import type { LiquidGroup } from '../../labware-ingred/types' -type Props = LiquidGroup & { +interface LiquidEditFormProps { + serialize: boolean canDelete: boolean - deleteLiquidGroup: () => unknown - cancelForm: () => unknown - saveForm: (liquidGroup: LiquidGroup) => unknown + deleteLiquidGroup: () => void + cancelForm: () => void + saveForm: (liquidGroup: LiquidGroup) => void + displayColor?: string + name?: string | null + description?: string | null } interface LiquidEditFormValues { @@ -69,17 +73,26 @@ export const liquidEditFormSchema: any = Yup.object().shape({ serialize: Yup.boolean(), }) -export function LiquidEditForm(props: Props): JSX.Element { - const { deleteLiquidGroup, cancelForm, canDelete, saveForm } = props +export function LiquidEditForm(props: LiquidEditFormProps): JSX.Element { + const { + deleteLiquidGroup, + cancelForm, + canDelete, + saveForm, + displayColor, + name: propName, + description: propDescription, + serialize, + } = props const selectedLiquid = useSelector(selectors.getSelectedLiquidGroupState) const nextGroupId = useSelector(selectors.getNextLiquidGroupId) const liquidId = selectedLiquid.liquidGroupId ?? nextGroupId const { t } = useTranslation(['form', 'button']) const initialValues: LiquidEditFormValues = { - name: props.name || '', - displayColor: props.displayColor ?? swatchColors(liquidId), - description: props.description || '', - serialize: props.serialize || false, + name: propName || '', + displayColor: displayColor ?? swatchColors(liquidId), + description: propDescription || '', + serialize: serialize || false, } const { @@ -94,6 +107,7 @@ export function LiquidEditForm(props: Props): JSX.Element { }) const name = watch('name') const description = watch('description') + const color = watch('displayColor') const handleLiquidEdits = (values: LiquidEditFormValues): void => { saveForm({ @@ -150,9 +164,10 @@ export function LiquidEditForm(props: Props): JSX.Element { control={control} render={({ field }) => ( { setValue('displayColor', color) + field.onChange(color) }} /> )} diff --git a/protocol-designer/src/components/LiquidsPage/index.tsx b/protocol-designer/src/components/LiquidsPage/index.tsx index 3b9f4f977fe..e6f4387e936 100644 --- a/protocol-designer/src/components/LiquidsPage/index.tsx +++ b/protocol-designer/src/components/LiquidsPage/index.tsx @@ -44,12 +44,6 @@ export function LiquidsPage(): JSX.Element { }) ) } - console.assert( - !(liquidGroupId && !selectedIngredFields), - `Expected selected liquid group "${String( - liquidGroupId - )}" to have fields in allIngredientGroupFields` - ) return showForm ? ( diff --git a/protocol-designer/src/components/StepEditForm/fields/FlowRateField/FlowRateInput.tsx b/protocol-designer/src/components/StepEditForm/fields/FlowRateField/FlowRateInput.tsx index 978990e1b64..06862663e97 100644 --- a/protocol-designer/src/components/StepEditForm/fields/FlowRateField/FlowRateInput.tsx +++ b/protocol-designer/src/components/StepEditForm/fields/FlowRateField/FlowRateInput.tsx @@ -7,19 +7,23 @@ import { FormGroup, RadioGroup, InputField, + Flex, + useHoverTooltip, + Tooltip, } from '@opentrons/components' import { getMainPagePortalEl } from '../../../portals/MainPageModalPortal' +import type { FieldProps } from '../../types' + import modalStyles from '../../../modals/modal.module.css' import stepFormStyles from '../../StepEditForm.module.css' import styles from './FlowRateInput.module.css' -import type { FieldProps } from '../../types' const DECIMALS_ALLOWED = 1 /** When flow rate is falsey (including 0), it means 'use default' */ export interface FlowRateInputProps extends FieldProps { defaultFlowRate?: number | null - flowRateType: 'aspirate' | 'dispense' + flowRateType: 'aspirate' | 'dispense' | 'blowout' label?: string | null minFlowRate: number maxFlowRate: number @@ -46,8 +50,10 @@ export const FlowRateInput = (props: FlowRateInputProps): JSX.Element => { minFlowRate, name, pipetteDisplayName, + tooltipContent, } = props - const { t } = useTranslation(['form', 'application']) + const [targetProps, tooltipProps] = useHoverTooltip() + const { t } = useTranslation(['form', 'application', 'shared']) const DEFAULT_LABEL = t('step_edit_form.field.flow_rate.label') const initialState: State = { @@ -112,7 +118,10 @@ export const FlowRateInput = (props: FlowRateInputProps): JSX.Element => { // show 0.1 not 0 as minimum, since bottom of range is non-inclusive const displayMinFlowRate = minFlowRate || Math.pow(10, -DECIMALS_ALLOWED) - const rangeDescription = `between ${displayMinFlowRate} and ${maxFlowRate}` + const rangeDescription = t('step_edit_form.field.flow_rate.range', { + min: displayMinFlowRate, + max: maxFlowRate, + }) const outOfBounds = modalFlowRateNum === 0 || minFlowRate > modalFlowRateNum || @@ -126,11 +135,14 @@ export const FlowRateInput = (props: FlowRateInputProps): JSX.Element => { // and pristinity only masks the outOfBounds error, not the correctDecimals error if (!modalUseDefault) { if (!Number.isNaN(modalFlowRateNum) && !correctDecimals) { - errorMessage = `a max of ${DECIMALS_ALLOWED} decimal place${ - DECIMALS_ALLOWED > 1 ? 's' : '' - } is allowed` + errorMessage = t('step_edit_form.field.flow_rate.error_decimals', { + decimals: `${DECIMALS_ALLOWED}`, + }) } else if (!isPristine && outOfBounds) { - errorMessage = `accepted range is ${displayMinFlowRate} to ${maxFlowRate}` + errorMessage = t('step_edit_form.field.flow_rate.error_out_of_bounds', { + min: displayMinFlowRate, + max: maxFlowRate, + }) } } @@ -155,21 +167,22 @@ export const FlowRateInput = (props: FlowRateInputProps): JSX.Element => { className={modalStyles.modal} buttons={[ { - children: 'Cancel', + children: t('shared:cancel'), onClick: cancelModal, }, { - children: 'Done', + children: t('shared:done'), onClick: makeSaveModal(allowSave), disabled: isPristine ? false : !allowSave, }, ]} > -

    Flow Rate

    +

    {DEFAULT_LABEL}

    - {`Our default aspirate speed is optimal for a ${pipetteDisplayName} - aspirating liquids with a viscosity similar to water`} + {t('step_edit_form.field.flow_rate.default_text', { + displayName: pipetteDisplayName, + })}
    @@ -199,21 +212,37 @@ export const FlowRateInput = (props: FlowRateInputProps): JSX.Element => { ) return ( - - - - + <> + {flowRateType === 'blowout' ? ( + + + {tooltipContent} + + ) : ( + + + + )} {showModal && FlowRateModal} - + ) } diff --git a/protocol-designer/src/components/StepEditForm/fields/FlowRateField/__tests__/FlowRateField.test.tsx b/protocol-designer/src/components/StepEditForm/fields/FlowRateField/__tests__/FlowRateField.test.tsx new file mode 100644 index 00000000000..2e6cea00cf8 --- /dev/null +++ b/protocol-designer/src/components/StepEditForm/fields/FlowRateField/__tests__/FlowRateField.test.tsx @@ -0,0 +1,84 @@ +import * as React from 'react' +import '@testing-library/jest-dom/vitest' +import { describe, it, vi, beforeEach, expect } from 'vitest' +import { fireEvent, screen } from '@testing-library/react' +import { fixtureP100096V2Specs } from '@opentrons/shared-data' +import { renderWithProviders } from '../../../../../__testing-utils__' +import { i18n } from '../../../../../localization' +import { getPipetteEntities } from '../../../../../step-forms/selectors' +import { FlowRateField } from '../index' + +vi.mock('../../../../../step-forms/selectors') +const render = (props: React.ComponentProps) => { + return renderWithProviders(, { + i18nInstance: i18n, + })[0] +} +const mockMockId = 'mockId' +describe('FlowRateField', () => { + let props: React.ComponentProps + + beforeEach(() => { + props = { + disabled: false, + flowRateType: 'aspirate', + volume: 100, + value: null, + name: 'flowRate', + tiprack: 'tipRack:opentrons_flex_96_tiprack_1000ul', + updateValue: vi.fn(), + onFieldBlur: vi.fn(), + onFieldFocus: vi.fn(), + pipetteId: mockMockId, + } + vi.mocked(getPipetteEntities).mockReturnValue({ + [mockMockId]: { + name: 'p50_single_flex', + spec: { + liquids: fixtureP100096V2Specs.liquids, + displayName: 'mockPipDisplayName', + } as any, + id: mockMockId, + tiprackLabwareDef: [ + { + parameters: { + loadName: 'opentrons_flex_96_tiprack_1000ul', + tipLength: 1000, + }, + metadata: { displayName: 'mockDisplayName' }, + } as any, + ], + tiprackDefURI: ['mockDefURI1', 'mockDefURI2'], + }, + }) + }) + it('renders the flowRateInput and clicking on it opens the modal with all the text', () => { + render(props) + screen.getByText('Flow Rate') + fireEvent.click(screen.getByRole('textbox')) + screen.getByText( + 'The default mockPipDisplayName flow rate is optimal for handling aqueous liquids' + ) + screen.getByText('aspirate speed') + screen.getByText('160 μL/s (default)') + screen.getByText('Custom') + screen.getByText('between 0.1 and Infinity') + screen.getByText('Cancel') + screen.getByText('Done') + }) + it('renders the information for blowout field', () => { + props.flowRateType = 'blowout' + render(props) + expect(screen.queryByText('Flow Rate')).not.toBeInTheDocument() + fireEvent.click(screen.getByRole('textbox')) + screen.getByText( + 'The default mockPipDisplayName flow rate is optimal for handling aqueous liquids' + ) + screen.getByText('blowout speed') + screen.getByText('80 μL/s (default)') + screen.getByText('Custom') + screen.getByText('between 0.1 and Infinity') + screen.getByText('Cancel') + screen.getByText('Done') + }) +}) diff --git a/protocol-designer/src/components/StepEditForm/fields/FlowRateField/index.tsx b/protocol-designer/src/components/StepEditForm/fields/FlowRateField/index.tsx index a482450d70e..165ec2553a1 100644 --- a/protocol-designer/src/components/StepEditForm/fields/FlowRateField/index.tsx +++ b/protocol-designer/src/components/StepEditForm/fields/FlowRateField/index.tsx @@ -1,11 +1,12 @@ import * as React from 'react' -import { FlowRateInput, FlowRateInputProps } from './FlowRateInput' +import { FlowRateInput } from './FlowRateInput' import { useSelector } from 'react-redux' import { selectors as stepFormSelectors } from '../../../../step-forms' -import { FieldProps } from '../../types' import { getMatchingTipLiquidSpecs } from '../../../../utils' +import type { FieldProps } from '../../types' +import type { FlowRateInputProps } from './FlowRateInput' -interface OP extends FieldProps { +interface FlowRateFieldProps extends FieldProps { flowRateType: FlowRateInputProps['flowRateType'] volume: unknown tiprack: unknown @@ -14,14 +15,14 @@ interface OP extends FieldProps { label?: FlowRateInputProps['label'] } -// Add a key to force re-constructing component when values change -export function FlowRateField(props: OP): JSX.Element { +export function FlowRateField(props: FlowRateFieldProps): JSX.Element { const { pipetteId, flowRateType, value, volume, tiprack, + name, ...passThruProps } = props const pipetteEntities = useSelector(stepFormSelectors.getPipetteEntities) @@ -41,20 +42,23 @@ export function FlowRateField(props: OP): JSX.Element { } else if (flowRateType === 'dispense') { defaultFlowRate = matchingTipLiquidSpecs?.defaultDispenseFlowRate.default ?? 0 + } else if (flowRateType === 'blowout') { + defaultFlowRate = + matchingTipLiquidSpecs?.defaultBlowOutFlowRate.default ?? 0 } } - return ( ) } diff --git a/protocol-designer/src/components/StepEditForm/fields/LabwareLocationField/index.tsx b/protocol-designer/src/components/StepEditForm/fields/LabwareLocationField/index.tsx index 072f7fa5e02..2cbb465c1fc 100644 --- a/protocol-designer/src/components/StepEditForm/fields/LabwareLocationField/index.tsx +++ b/protocol-designer/src/components/StepEditForm/fields/LabwareLocationField/index.tsx @@ -1,12 +1,8 @@ import * as React from 'react' import { useSelector } from 'react-redux' import { useTranslation } from 'react-i18next' +import { getModuleDisplayName } from '@opentrons/shared-data' import { - getModuleDisplayName, - WASTE_CHUTE_CUTOUT, -} from '@opentrons/shared-data' -import { - getAdditionalEquipmentEntities, getLabwareEntities, getModuleEntities, } from '../../../../step-forms/selectors' @@ -14,7 +10,6 @@ import { getRobotStateAtActiveItem, getUnoccupiedLabwareLocationOptions, } from '../../../../top-selectors/labware-locations' -import { getHasWasteChute } from '../../../labware' import { StepFormDropdown } from '../StepFormDropdownField' export function LabwareLocationField( @@ -27,32 +22,18 @@ export function LabwareLocationField( const labwareEntities = useSelector(getLabwareEntities) const robotState = useSelector(getRobotStateAtActiveItem) const moduleEntities = useSelector(getModuleEntities) - const additionalEquipmentEntities = useSelector( - getAdditionalEquipmentEntities - ) - const hasWasteChute = getHasWasteChute(additionalEquipmentEntities) const isLabwareOffDeck = labware != null ? robotState?.labware[labware]?.slot === 'offDeck' : false - const displayWasteChuteValue = - useGripper && hasWasteChute && !isLabwareOffDeck let unoccupiedLabwareLocationsOptions = useSelector(getUnoccupiedLabwareLocationOptions) ?? [] - if (isLabwareOffDeck && hasWasteChute) { - unoccupiedLabwareLocationsOptions = unoccupiedLabwareLocationsOptions.filter( - option => - option.value !== 'offDeck' && option.value !== WASTE_CHUTE_CUTOUT - ) - } else if (useGripper || isLabwareOffDeck) { + if (useGripper || isLabwareOffDeck) { unoccupiedLabwareLocationsOptions = unoccupiedLabwareLocationsOptions.filter( option => option.value !== 'offDeck' ) - } else if (!displayWasteChuteValue) { - unoccupiedLabwareLocationsOptions = unoccupiedLabwareLocationsOptions.filter( - option => option.name !== 'Waste Chute in D3' - ) } + const location: string = value as string const bothFieldsSelected = labware != null && value != null diff --git a/protocol-designer/src/components/StepEditForm/fields/TipPositionField/TipPositionModal.tsx b/protocol-designer/src/components/StepEditForm/fields/TipPositionField/TipPositionModal.tsx index 2a303f92c2f..2ec2e7f41ab 100644 --- a/protocol-designer/src/components/StepEditForm/fields/TipPositionField/TipPositionModal.tsx +++ b/protocol-designer/src/components/StepEditForm/fields/TipPositionField/TipPositionModal.tsx @@ -93,12 +93,12 @@ export const TipPositionModal = ( } => { if (getIsTouchTipField(zSpec?.name ?? '')) { return { - maxMmFromBottom: utils.roundValue(wellDepthMm), - minMmFromBottom: utils.roundValue(wellDepthMm / 2), + maxMmFromBottom: utils.roundValue(wellDepthMm, 'up'), + minMmFromBottom: utils.roundValue(wellDepthMm / 2, 'up'), } } return { - maxMmFromBottom: utils.roundValue(wellDepthMm * 2), + maxMmFromBottom: utils.roundValue(wellDepthMm * 2, 'up'), minMmFromBottom: 0, } } @@ -138,10 +138,10 @@ export const TipPositionModal = ( return utils.getErrorText({ errors, minMm: min, maxMm: max, isPristine, t }) } - const roundedXMin = utils.roundValue(xMinWidth) - const roundedYMin = utils.roundValue(yMinWidth) - const roundedXMax = utils.roundValue(xMaxWidth) - const roundedYMax = utils.roundValue(yMaxWidth) + const roundedXMin = utils.roundValue(xMinWidth, 'up') + const roundedYMin = utils.roundValue(yMinWidth, 'up') + const roundedXMax = utils.roundValue(xMaxWidth, 'down') + const roundedYMax = utils.roundValue(yMaxWidth, 'down') const zErrorText = createErrorText(zErrors, minMmFromBottom, maxMmFromBottom) const xErrorText = createErrorText(xErrors, roundedXMin, roundedXMax) @@ -234,6 +234,7 @@ export const TipPositionModal = ( yValue != null && (parseInt(yValue) > PERCENT_RANGE_TO_SHOW_WARNING * yMaxWidth || parseInt(yValue) < PERCENT_RANGE_TO_SHOW_WARNING * yMinWidth) + const isZValueAtBottom = zValue != null && zValue === '0' const TipPositionInputField = !isDefault ? ( @@ -315,7 +316,8 @@ export const TipPositionModal = (

    {t(`tip_position.body.${zSpec?.name}`)}

    - {(isXValueNearEdge || isYValueNearEdge) && !isDefault ? ( + {(isXValueNearEdge || isYValueNearEdge || isZValueAtBottom) && + !isDefault ? ( { if (getIsTouchTipField(name)) { return { - maxMmFromBottom: utils.roundValue(wellDepthMm), - minMmFromBottom: utils.roundValue(wellDepthMm / 2), + maxMmFromBottom: utils.roundValue(wellDepthMm, 'up'), + minMmFromBottom: utils.roundValue(wellDepthMm / 2, 'up'), } } return { - maxMmFromBottom: utils.roundValue(wellDepthMm * 2), + maxMmFromBottom: utils.roundValue(wellDepthMm * 2, 'up'), minMmFromBottom: 0, } } @@ -148,7 +148,7 @@ export function ZTipPositionModal(props: ZTipPositionModalProps): JSX.Element { const handleIncrementDecrement = (delta: number): void => { const prevValue = value === null ? defaultMm : Number(value) setIsDefault(false) - handleChange(utils.roundValue(prevValue + delta)) + handleChange(utils.roundValue(prevValue + delta, 'up')) } const makeHandleIncrement = (step: number): (() => void) => () => { diff --git a/protocol-designer/src/components/StepEditForm/fields/TipPositionField/__tests__/TipPositionModal.test.tsx b/protocol-designer/src/components/StepEditForm/fields/TipPositionField/__tests__/TipPositionModal.test.tsx index 6054bd2eb2d..28b3afbb46d 100644 --- a/protocol-designer/src/components/StepEditForm/fields/TipPositionField/__tests__/TipPositionModal.test.tsx +++ b/protocol-designer/src/components/StepEditForm/fields/TipPositionField/__tests__/TipPositionModal.test.tsx @@ -66,7 +66,7 @@ describe('TipPositionModal', () => { render(props) screen.getByText('warning') screen.getByText( - 'The X and/or Y position value is close to edge of the well and might collide with it' + 'One or more position offset values are close to the edge of the well and might collide with it' ) }) it('renders the alert if the x/y position values are too close to the max/min for y value', () => { @@ -74,7 +74,7 @@ describe('TipPositionModal', () => { render(props) screen.getByText('warning') screen.getByText( - 'The X and/or Y position value is close to edge of the well and might collide with it' + 'One or more position offset values are close to the edge of the well and might collide with it' ) }) it('renders the custom options, captions, and visual', () => { @@ -82,9 +82,9 @@ describe('TipPositionModal', () => { fireEvent.click(screen.getByRole('radio', { name: 'Custom' })) expect(screen.getAllByRole('textbox', { name: '' })).toHaveLength(3) screen.getByText('X position') - screen.getByText('between -5.1 and 5.2') + screen.getByText('between -5.1 and 5.1') screen.getByText('Y position') - screen.getByText('between -5.2 and 5.3') + screen.getByText('between -5.2 and 5.2') screen.getByText('Z position') screen.getByText('between 0 and 100') screen.getByText('mock TipPositionViz') @@ -129,8 +129,8 @@ describe('TipPositionModal', () => { fireEvent.click(screen.getByText('done')) // display out of bounds error screen.getByText('accepted range is 0 to 100') - screen.getByText('accepted range is -5.2 to 5.3') - screen.getByText('accepted range is -5.1 to 5.2') + screen.getByText('accepted range is -5.2 to 5.2') + screen.getByText('accepted range is -5.1 to 5.1') const xInputField = screen.getAllByRole('textbox', { name: '' })[0] fireEvent.change(xInputField, { target: { value: 3.55555 } }) fireEvent.click(screen.getByText('done')) diff --git a/protocol-designer/src/components/StepEditForm/fields/TipPositionField/utils.ts b/protocol-designer/src/components/StepEditForm/fields/TipPositionField/utils.ts index 96ed4729d49..4648aa78933 100644 --- a/protocol-designer/src/components/StepEditForm/fields/TipPositionField/utils.ts +++ b/protocol-designer/src/components/StepEditForm/fields/TipPositionField/utils.ts @@ -1,3 +1,4 @@ +import floor from 'lodash/floor' import round from 'lodash/round' import { getIsTouchTipField } from '../../../../form-types' import { @@ -46,8 +47,20 @@ export function getDefaultMmFromBottom(args: { } } -export const roundValue = (value: number | string | null): number => { - return value === null ? 0 : round(Number(value), DECIMALS_ALLOWED) +export const roundValue = ( + value: number | string | null, + direction: 'up' | 'down' +): number => { + if (value === null) return 0 + + switch (direction) { + case 'up': { + return round(Number(value), DECIMALS_ALLOWED) + } + case 'down': { + return floor(Number(value), DECIMALS_ALLOWED) + } + } } const OUT_OF_BOUNDS: 'OUT_OF_BOUNDS' = 'OUT_OF_BOUNDS' diff --git a/protocol-designer/src/components/StepEditForm/fields/TiprackField.tsx b/protocol-designer/src/components/StepEditForm/fields/TiprackField.tsx index a9dceb482a2..7c9f2cea2a0 100644 --- a/protocol-designer/src/components/StepEditForm/fields/TiprackField.tsx +++ b/protocol-designer/src/components/StepEditForm/fields/TiprackField.tsx @@ -1,32 +1,62 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' import { useSelector } from 'react-redux' -import { FormGroup, DropdownField } from '@opentrons/components' +import { + FormGroup, + DropdownField, + useHoverTooltip, + Tooltip, + Box, +} from '@opentrons/components' import { selectors as uiLabwareSelectors } from '../../../ui/labware' -import styles from '../StepEditForm.module.css' - +import { getPipetteEntities } from '../../../step-forms/selectors' import type { FieldProps } from '../types' -export function TiprackField(props: FieldProps): JSX.Element { - const { name, value, onFieldBlur, onFieldFocus, updateValue } = props - const { t } = useTranslation('form') +import styles from '../StepEditForm.module.css' + +interface TiprackFieldProps extends FieldProps { + pipetteId?: unknown +} +export function TiprackField(props: TiprackFieldProps): JSX.Element { + const { + name, + value, + onFieldBlur, + onFieldFocus, + updateValue, + pipetteId, + } = props + const { t } = useTranslation(['form', 'tooltip']) + const [targetProps, tooltipProps] = useHoverTooltip() + const pipetteEntities = useSelector(getPipetteEntities) const options = useSelector(uiLabwareSelectors.getTiprackOptions) + const defaultTiprackUris = + pipetteId != null ? pipetteEntities[pipetteId as string].tiprackDefURI : [] + const tiprackOptions = options.filter(option => + defaultTiprackUris.includes(option.value) + ) + const hasMissingTiprack = defaultTiprackUris.length > tiprackOptions.length return ( - - ) => { - updateValue(e.currentTarget.value) - }} - /> - + + + ) => { + updateValue(e.currentTarget.value) + }} + /> + + {hasMissingTiprack ? ( + {t('tooltip:missing_tiprack')} + ) : null} + ) } diff --git a/protocol-designer/src/components/StepEditForm/fields/__tests__/TiprackField.test.tsx b/protocol-designer/src/components/StepEditForm/fields/__tests__/TiprackField.test.tsx new file mode 100644 index 00000000000..063cc9b382c --- /dev/null +++ b/protocol-designer/src/components/StepEditForm/fields/__tests__/TiprackField.test.tsx @@ -0,0 +1,58 @@ +import * as React from 'react' +import { describe, it, vi, beforeEach } from 'vitest' +import { screen } from '@testing-library/react' +import { i18n } from '../../../../localization' +import { getPipetteEntities } from '../../../../step-forms/selectors' +import { renderWithProviders } from '../../../../__testing-utils__' +import { getTiprackOptions } from '../../../../ui/labware/selectors' +import { TiprackField } from '../TiprackField' + +vi.mock('../../../../ui/labware/selectors') +vi.mock('../../../../step-forms/selectors') + +const render = (props: React.ComponentProps) => { + return renderWithProviders(, { + i18nInstance: i18n, + })[0] +} +const mockMockId = 'mockId' +describe('TiprackField', () => { + let props: React.ComponentProps + + beforeEach(() => { + props = { + disabled: false, + value: null, + name: 'tipRackt', + updateValue: vi.fn(), + onFieldBlur: vi.fn(), + onFieldFocus: vi.fn(), + pipetteId: mockMockId, + } + vi.mocked(getPipetteEntities).mockReturnValue({ + [mockMockId]: { + name: 'p50_single_flex', + spec: {} as any, + id: mockMockId, + tiprackLabwareDef: [], + tiprackDefURI: ['mockDefURI1', 'mockDefURI2'], + }, + }) + vi.mocked(getTiprackOptions).mockReturnValue([ + { + value: 'mockDefURI1', + name: 'tiprack1', + }, + { + value: 'mockDefURI2', + name: 'tiprack2', + }, + ]) + }) + it('renders the dropdown field and texts', () => { + render(props) + screen.getByText('tip rack') + screen.getByText('tiprack1') + screen.getByText('tiprack2') + }) +}) diff --git a/protocol-designer/src/components/StepEditForm/forms/MixForm.tsx b/protocol-designer/src/components/StepEditForm/forms/MixForm.tsx index ef1b408cfe4..324c1c9754c 100644 --- a/protocol-designer/src/components/StepEditForm/forms/MixForm.tsx +++ b/protocol-designer/src/components/StepEditForm/forms/MixForm.tsx @@ -52,7 +52,10 @@ export const MixForm = (props: StepFormProps): JSX.Element => {
- + {is96Channel ? ( ) : null} @@ -210,6 +213,13 @@ export const MixForm = (props: StepFormProps): JSX.Element => { stepType: formData.stepType, })} /> + { stepType: formData.stepType, })} /> + {
- + {is96Channel ? ( ) : null} diff --git a/protocol-designer/src/components/__tests__/EditModules.test.tsx b/protocol-designer/src/components/__tests__/EditModules.test.tsx index 2cb2ed8c55f..7f50b877744 100644 --- a/protocol-designer/src/components/__tests__/EditModules.test.tsx +++ b/protocol-designer/src/components/__tests__/EditModules.test.tsx @@ -1,19 +1,27 @@ import * as React from 'react' import { screen } from '@testing-library/react' import { vi, beforeEach, describe, it } from 'vitest' +import { + FLEX_ROBOT_TYPE, + OT2_ROBOT_TYPE, + TEMPERATURE_MODULE_TYPE, +} from '@opentrons/shared-data' import { i18n } from '../../localization' import { getInitialDeckSetup } from '../../step-forms/selectors' import { getDismissedHints } from '../../tutorial/selectors' import { EditModules } from '../EditModules' import { EditModulesModal } from '../modals/EditModulesModal' import { renderWithProviders } from '../../__testing-utils__' +import { getRobotType } from '../../file-data/selectors' +import { EditMultipleModulesModal } from '../modals/EditModulesModal/EditMultipleModulesModal' import type { HintKey } from '../../tutorial' vi.mock('../../step-forms/selectors') +vi.mock('../modals/EditModulesModal/EditMultipleModulesModal') vi.mock('../modals/EditModulesModal') vi.mock('../../tutorial/selectors') - +vi.mock('../../file-data/selectors') const render = (props: React.ComponentProps) => { return renderWithProviders(, { i18nInstance: i18n, @@ -51,11 +59,21 @@ describe('EditModules', () => { vi.mocked(EditModulesModal).mockReturnValue(
mock EditModulesModal
) + vi.mocked(EditMultipleModulesModal).mockReturnValue( +
mock EditMultipleModulesModal
+ ) vi.mocked(getDismissedHints).mockReturnValue([hintKey]) + vi.mocked(getRobotType).mockReturnValue(OT2_ROBOT_TYPE) }) - it('renders the edit modules modal', () => { + it('renders the edit modules modal for single modules', () => { render(props) screen.getByText('mock EditModulesModal') }) + it('renders multiple edit modules modal', () => { + props.moduleToEdit.moduleType = TEMPERATURE_MODULE_TYPE + vi.mocked(getRobotType).mockReturnValue(FLEX_ROBOT_TYPE) + render(props) + screen.getByText('mock EditMultipleModulesModal') + }) }) diff --git a/protocol-designer/src/components/lists/TitledStepList.tsx b/protocol-designer/src/components/lists/TitledStepList.tsx index 0e3da16c542..1b88b291b1e 100644 --- a/protocol-designer/src/components/lists/TitledStepList.tsx +++ b/protocol-designer/src/components/lists/TitledStepList.tsx @@ -110,7 +110,12 @@ export function TitledStepList(props: Props): JSX.Element {
)} {iconName && ( - + )}

{props.title}

{collapsible && ( diff --git a/protocol-designer/src/components/modals/AnnouncementModal/announcements.tsx b/protocol-designer/src/components/modals/AnnouncementModal/announcements.tsx index aab430bf549..b10c6d75407 100644 --- a/protocol-designer/src/components/modals/AnnouncementModal/announcements.tsx +++ b/protocol-designer/src/components/modals/AnnouncementModal/announcements.tsx @@ -265,5 +265,39 @@ export const useAnnouncements = (): Announcement[] => { ), }, + { + announcementKey: 'customParamsAndMultiTipAndModule8.1', + image: , + heading: t('announcements.header', { pd: PD }), + message: ( + <> +

+ {t('announcements.customParamsAndMultiTipAndModule.body1', { + pd: PD, + })} +

+
    +
  • {t('announcements.customParamsAndMultiTipAndModule.body2')}
  • +
  • + }} + /> +
  • +
  • {t('announcements.customParamsAndMultiTipAndModule.body4')}
  • +
  • {t('announcements.customParamsAndMultiTipAndModule.body5')}
  • +
+

+ }} + values={{ app: APP }} + /> +

+ + ), + }, ] } diff --git a/protocol-designer/src/components/modals/CreateFileWizard/ModulesAndOtherTile.tsx b/protocol-designer/src/components/modals/CreateFileWizard/ModulesAndOtherTile.tsx index bcebf6313c3..cc0906c34b8 100644 --- a/protocol-designer/src/components/modals/CreateFileWizard/ModulesAndOtherTile.tsx +++ b/protocol-designer/src/components/modals/CreateFileWizard/ModulesAndOtherTile.tsx @@ -30,14 +30,13 @@ import { getModuleDisplayName, getModuleType, FLEX_ROBOT_TYPE, - THERMOCYCLER_MODULE_TYPE, MAGNETIC_BLOCK_TYPE, + THERMOCYCLER_MODULE_TYPE, } from '@opentrons/shared-data' import { getIsCrashablePipetteSelected } from '../../../step-forms' import gripperImage from '../../../images/flex_gripper.png' import wasteChuteImage from '../../../images/waste_chute.png' import trashBinImage from '../../../images/flex_trash_bin.png' -import { getEnableMoam } from '../../../feature-flags/selectors' import { uuid } from '../../../utils' import { selectors as featureFlagSelectors } from '../../../feature-flags' import { CrashInfoBox, ModuleDiagram } from '../../modules' @@ -45,9 +44,8 @@ import { ModuleFields } from '../FilePipettesModal/ModuleFields' import { GoBack } from './GoBack' import { getCrashableModuleSelected, - getDisabledEquipment, - getNextAvailableModuleSlot, - getTrashBinOptionDisabled, + getNumSlotsAvailable, + getTrashOptionDisabled, } from './utils' import { EquipmentOption } from './EquipmentOption' import { HandleEnter } from './HandleEnter' @@ -192,15 +190,10 @@ export function ModulesAndOtherTile(props: WizardTileProps): JSX.Element { function FlexModuleFields(props: WizardTileProps): JSX.Element { const { watch, setValue } = props - const enableMoamFf = useSelector(getEnableMoam) const modules = watch('modules') const additionalEquipment = watch('additionalEquipment') const moduleTypesOnDeck = modules != null ? Object.values(modules).map(module => module.type) : [] - const trashBinDisabled = getTrashBinOptionDisabled({ - additionalEquipment, - modules, - }) const handleSetEquipmentOption = (equipment: AdditionalEquipment): void => { if (additionalEquipment.includes(equipment)) { @@ -209,6 +202,11 @@ function FlexModuleFields(props: WizardTileProps): JSX.Element { setValue('additionalEquipment', [...additionalEquipment, equipment]) } } + const trashBinDisabled = getTrashOptionDisabled({ + additionalEquipment, + modules, + trashType: 'trashBin', + }) React.useEffect(() => { if (trashBinDisabled) { @@ -220,21 +218,15 @@ function FlexModuleFields(props: WizardTileProps): JSX.Element { {FLEX_SUPPORTED_MODULE_MODELS.map(moduleModel => { const moduleType = getModuleType(moduleModel) - const moduleOnDeck = moduleTypesOnDeck.includes(moduleType) + const isModuleOnDeck = moduleTypesOnDeck.includes(moduleType) - let defaultSlot = getNextAvailableModuleSlot( - modules, - additionalEquipment - ) + let isDisabled = + getNumSlotsAvailable(modules, additionalEquipment) === 0 + // special-casing TC since it takes up 2 slots if (moduleType === THERMOCYCLER_MODULE_TYPE) { - defaultSlot = 'B1' - } else if (moduleType === MAGNETIC_BLOCK_TYPE) { - defaultSlot = 'D2' + isDisabled = getNumSlotsAvailable(modules, additionalEquipment) === 1 } - const isDisabled = getDisabledEquipment({ - additionalEquipment, - modules, - })?.includes(moduleType) + const handleMultiplesClick = (num: number): void => { const temperatureModules = modules != null @@ -250,10 +242,7 @@ function FlexModuleFields(props: WizardTileProps): JSX.Element { [uuid()]: { model: moduleModel, type: moduleType, - slot: getNextAvailableModuleSlot( - modules, - additionalEquipment - ), + slot: null, }, }) } @@ -270,11 +259,8 @@ function FlexModuleFields(props: WizardTileProps): JSX.Element { } const handleOnClick = (): void => { - if ( - (moduleType !== TEMPERATURE_MODULE_TYPE && enableMoamFf) || - !enableMoamFf - ) { - if (moduleOnDeck) { + if (moduleType !== TEMPERATURE_MODULE_TYPE) { + if (isModuleOnDeck) { const updatedModules = modules != null ? Object.fromEntries( @@ -290,7 +276,7 @@ function FlexModuleFields(props: WizardTileProps): JSX.Element { [uuid()]: { model: moduleModel, type: moduleType, - slot: defaultSlot, + slot: DEFAULT_SLOT_MAP[moduleModel], }, }) } @@ -301,13 +287,17 @@ function FlexModuleFields(props: WizardTileProps): JSX.Element { } text={getModuleDisplayName(moduleModel)} - disabled={isDisabled && !moduleOnDeck} + disabled={ + moduleType === MAGNETIC_BLOCK_TYPE + ? false + : isDisabled && !isModuleOnDeck + } onClick={handleOnClick} multiples={ - moduleType === TEMPERATURE_MODULE_TYPE && enableMoamFf + moduleType === TEMPERATURE_MODULE_TYPE ? { maxItems: MAX_TEMPERATURE_MODULES, setValue: handleMultiplesClick, @@ -321,9 +311,7 @@ function FlexModuleFields(props: WizardTileProps): JSX.Element { } : undefined } - showCheckbox={ - enableMoamFf ? moduleType !== TEMPERATURE_MODULE_TYPE : true - } + showCheckbox={moduleType !== TEMPERATURE_MODULE_TYPE} /> ) })} @@ -345,11 +333,11 @@ function FlexModuleFields(props: WizardTileProps): JSX.Element { robotType={FLEX_ROBOT_TYPE} onClick={() => handleSetEquipmentOption('wasteChute')} isSelected={additionalEquipment.includes('wasteChute')} - disabled={ - modules != null - ? Object.values(modules).some(module => module.slot === 'D3') - : false - } + disabled={getTrashOptionDisabled({ + additionalEquipment, + modules, + trashType: 'wasteChute', + })} image={ { - if (selectedValues.length === 0) { - setValue(`pipettesByMount.${mount}.tiprackDefURI`, [ - tiprackOptions[0]?.value ?? '', - ]) - } - }, [selectedValues, setValue, tiprackOptions]) + setValue(`pipettesByMount.${mount}.tiprackDefURI`, [ + tiprackOptions[0]?.value ?? '', + ]) + }, []) return ( { next = screen.getByRole('button', { name: 'Next' }) fireEvent.click(next) screen.getByText('Step 3 / 6') - // select 10uL tipracks + // un-select default 10uL tiprack then select again + fireEvent.click(screen.getByLabelText('EquipmentOption_flex_10uL tipracks')) fireEvent.click(screen.getByLabelText('EquipmentOption_flex_10uL tipracks')) next = screen.getByRole('button', { name: 'Next' }) fireEvent.click(next) diff --git a/protocol-designer/src/components/modals/CreateFileWizard/__tests__/EquipmentOption.test.tsx b/protocol-designer/src/components/modals/CreateFileWizard/__tests__/EquipmentOption.test.tsx index c83b1e99404..6b5978338d1 100644 --- a/protocol-designer/src/components/modals/CreateFileWizard/__tests__/EquipmentOption.test.tsx +++ b/protocol-designer/src/components/modals/CreateFileWizard/__tests__/EquipmentOption.test.tsx @@ -39,7 +39,7 @@ describe('EquipmentOption', () => { } render(props) expect(screen.getByLabelText('EquipmentOption_flex_mockText')).toHaveStyle( - `background-color: ${COLORS.grey10}` + `background-color: ${COLORS.white}` ) }) it('renders the equipment option without check not selected and image', () => { @@ -55,7 +55,7 @@ describe('EquipmentOption', () => { screen.getByLabelText('EquipmentOption_checkbox-blank-outline') ).toHaveStyle(`color: ${COLORS.grey50}`) expect(screen.getByLabelText('EquipmentOption_flex_mockText')).toHaveStyle( - `border: 1px ${BORDERS.styleSolid} ${COLORS.grey35}` + `border: 1px ${BORDERS.styleSolid} ${COLORS.grey30}` ) }) it('renders the equipment option without check selected', () => { diff --git a/protocol-designer/src/components/modals/CreateFileWizard/__tests__/ModulesAndOtherTile.test.tsx b/protocol-designer/src/components/modals/CreateFileWizard/__tests__/ModulesAndOtherTile.test.tsx index 63da7f3ed30..ba9924ee13e 100644 --- a/protocol-designer/src/components/modals/CreateFileWizard/__tests__/ModulesAndOtherTile.test.tsx +++ b/protocol-designer/src/components/modals/CreateFileWizard/__tests__/ModulesAndOtherTile.test.tsx @@ -5,10 +5,7 @@ import { fireEvent, screen, cleanup } from '@testing-library/react' import { FLEX_ROBOT_TYPE, OT2_ROBOT_TYPE } from '@opentrons/shared-data' import { renderWithProviders } from '../../../../__testing-utils__' import { i18n } from '../../../../localization' -import { - getDisableModuleRestrictions, - getEnableMoam, -} from '../../../../feature-flags/selectors' +import { getDisableModuleRestrictions } from '../../../../feature-flags/selectors' import { CrashInfoBox } from '../../../modules' import { ModuleFields } from '../../FilePipettesModal/ModuleFields' import { ModulesAndOtherTile } from '../ModulesAndOtherTile' @@ -61,7 +58,6 @@ describe('ModulesAndOtherTile', () => { ...props, ...mockWizardTileProps, } as WizardTileProps - vi.mocked(getEnableMoam).mockReturnValue(true) vi.mocked(CrashInfoBox).mockReturnValue(
mock CrashInfoBox
) vi.mocked(EquipmentOption).mockReturnValue(
mock EquipmentOption
) vi.mocked(getDisableModuleRestrictions).mockReturnValue(false) diff --git a/protocol-designer/src/components/modals/CreateFileWizard/__tests__/PipetteTipsTile.test.tsx b/protocol-designer/src/components/modals/CreateFileWizard/__tests__/PipetteTipsTile.test.tsx index 821acd65ef6..ce5e29f06a8 100644 --- a/protocol-designer/src/components/modals/CreateFileWizard/__tests__/PipetteTipsTile.test.tsx +++ b/protocol-designer/src/components/modals/CreateFileWizard/__tests__/PipetteTipsTile.test.tsx @@ -51,6 +51,7 @@ const mockWizardTileProps: Partial = { proceed: vi.fn(), watch: vi.fn((name: keyof typeof values) => values[name]) as any, getValues: vi.fn(() => values) as any, + setValue: vi.fn(), } const fixtureTipRack10ul = { diff --git a/protocol-designer/src/components/modals/CreateFileWizard/__tests__/utils.test.tsx b/protocol-designer/src/components/modals/CreateFileWizard/__tests__/utils.test.tsx index 240120c8b92..a8d59634e0b 100644 --- a/protocol-designer/src/components/modals/CreateFileWizard/__tests__/utils.test.tsx +++ b/protocol-designer/src/components/modals/CreateFileWizard/__tests__/utils.test.tsx @@ -1,22 +1,18 @@ import { it, describe, expect } from 'vitest' import { FLEX_ROBOT_TYPE, - HEATERSHAKER_MODULE_TYPE, SINGLE_RIGHT_SLOT_FIXTURE, - TEMPERATURE_MODULE_TYPE, - THERMOCYCLER_MODULE_TYPE, } from '@opentrons/shared-data' import { FLEX_TRASH_DEFAULT_SLOT, getUnoccupiedStagingAreaSlots, getTrashSlot, - getNextAvailableModuleSlot, - getDisabledEquipment, - getTrashBinOptionDisabled, + getTrashOptionDisabled, + getNumSlotsAvailable, } from '../utils' import { STANDARD_EMPTY_SLOTS } from '../StagingAreaTile' import type { FormPipettesByMount } from '../../../../step-forms' -import type { FormState } from '../types' +import type { AdditionalEquipment, FormState } from '../types' let MOCK_FORM_STATE = { fields: { @@ -56,118 +52,129 @@ describe('getUnoccupiedStagingAreaSlots', () => { { cutoutId: 'cutoutD3', cutoutFixtureId: SINGLE_RIGHT_SLOT_FIXTURE }, ]) }) - describe('getNextAvailableModuleSlot', () => { - it('should return D1 when there are no modules or staging areas', () => { - const result = getNextAvailableModuleSlot(null, []) - expect(result).toStrictEqual('D1') - }) - it('should return a C3 when all the modules are on the deck', () => { - const result = getNextAvailableModuleSlot( - { - 0: { - model: 'magneticBlockV1', - type: 'magneticBlockType', - slot: 'D1', - }, - 1: { - model: 'thermocyclerModuleV2', - type: 'thermocyclerModuleType', - slot: 'B1', - }, - 2: { - model: 'temperatureModuleV2', - type: 'temperatureModuleType', - slot: 'C1', - }, - }, - [] - ) - expect(result).toStrictEqual('C3') - }) +}) +describe('getNumSlotsAvailable', () => { + it('should return 8 when there are no modules or additional equipment', () => { + const result = getNumSlotsAvailable(null, []) + expect(result).toBe(8) }) - it('should return an empty string when all the modules and staging area slots are on the deck without TC', () => { - const result = getNextAvailableModuleSlot( - { - 0: { - model: 'heaterShakerModuleV1', - type: 'heaterShakerModuleType', - slot: 'D1', - }, - 1: { - model: 'temperatureModuleV2', - type: 'temperatureModuleType', - slot: 'C1', - }, - 2: { - model: 'temperatureModuleV2', - type: 'temperatureModuleType', - slot: 'B1', - }, + it('should return 0 when there is a TC and 7 modules', () => { + const mockModules = { + 0: { + model: 'heaterShakerModuleV1', + type: 'heaterShakerModuleType', + slot: 'D1', }, - [ - 'stagingArea_cutoutA3', - 'stagingArea_cutoutB3', - 'stagingArea_cutoutC3', - 'stagingArea_cutoutD3', - 'trashBin', - ] - ) - expect(result).toStrictEqual('') + 1: { + model: 'temperatureModuleV2', + type: 'temperatureModuleType', + slot: 'D3', + }, + 2: { + model: 'temperatureModuleV2', + type: 'temperatureModuleType', + slot: 'C1', + }, + 3: { + model: 'temperatureModuleV2', + type: 'temperatureModuleType', + slot: 'B3', + }, + 4: { + model: 'thermocyclerModuleV2', + type: 'thermocyclerModuleType', + slot: 'B1', + }, + 5: { + model: 'temperatureModuleV2', + type: 'temperatureModuleType', + slot: 'A3', + }, + 6: { + model: 'temperatureModuleV2', + type: 'temperatureModuleType', + slot: 'C3', + }, + } as any + const result = getNumSlotsAvailable(mockModules, []) + expect(result).toBe(0) }) - it('should return an empty string when all the modules and staging area slots are on the deck with TC', () => { - const result = getNextAvailableModuleSlot( - { - 0: { - model: 'heaterShakerModuleV1', - type: 'heaterShakerModuleType', - slot: 'D1', - }, - 1: { - model: 'thermocyclerModuleV2', - type: 'thermocyclerModuleType', - slot: 'B1', - }, + it('should return 1 when there are 9 additional equipment and 1 is a waste chute on the staging area and one is a gripper', () => { + const mockAdditionalEquipment: AdditionalEquipment[] = [ + 'trashBin', + 'stagingArea_cutoutA3', + 'stagingArea_cutoutB3', + 'stagingArea_cutoutC3', + 'stagingArea_cutoutD3', + 'wasteChute', + 'trashBin', + 'gripper', + 'trashBin', + ] + const result = getNumSlotsAvailable(null, mockAdditionalEquipment) + expect(result).toBe(1) + }) + it('should return 8 even when there is a magnetic block', () => { + const mockModules = { + 0: { + model: 'magneticBlockV1', + type: 'magneticBlockType', + slot: 'B2', }, - [ - 'stagingArea_cutoutA3', - 'stagingArea_cutoutB3', - 'stagingArea_cutoutC3', - 'stagingArea_cutoutD3', - 'trashBin', - ] - ) - expect(result).toStrictEqual('') + } as any + const result = getNumSlotsAvailable(mockModules, []) + expect(result).toBe(8) }) }) -describe('getNextAvailableModuleSlot', () => { - it('should return nothing as disabled', () => { - const result = getDisabledEquipment({ - additionalEquipment: [], - modules: null, - }) - expect(result).toStrictEqual([]) +describe('getTrashSlot', () => { + it('should return the default slot A3 when there is no staging area or module in that slot', () => { + MOCK_FORM_STATE = { + ...MOCK_FORM_STATE, + additionalEquipment: ['trashBin'], + } + const result = getTrashSlot(MOCK_FORM_STATE) + expect(result).toBe(FLEX_TRASH_DEFAULT_SLOT) + }) + it('should return cutoutA1 when there is a staging area in slot A3', () => { + MOCK_FORM_STATE = { + ...MOCK_FORM_STATE, + additionalEquipment: ['stagingArea_cutoutA3'], + } + const result = getTrashSlot(MOCK_FORM_STATE) + expect(result).toBe('cutoutA1') }) - it('should return the TC as disabled', () => { - const result = getDisabledEquipment({ - additionalEquipment: [], +}) +describe('getTrashOptionDisabled', () => { + it('returns false when there is a trash bin already', () => { + const result = getTrashOptionDisabled({ + trashType: 'trashBin', + additionalEquipment: ['trashBin'], modules: { 0: { model: 'heaterShakerModuleV1', type: 'heaterShakerModuleType', - slot: 'A1', + slot: 'D1', }, }, }) - expect(result).toStrictEqual([THERMOCYCLER_MODULE_TYPE]) + expect(result).toBe(false) }) - it('should return all module types if there is no available slot', () => { - const result = getDisabledEquipment({ + it('returns false when there is an available slot', () => { + const result = getTrashOptionDisabled({ + trashType: 'trashBin', + additionalEquipment: ['trashBin'], + modules: null, + }) + expect(result).toBe(false) + }) + it('returns true when there is no available slot and trash bin is not selected yet', () => { + const result = getTrashOptionDisabled({ + trashType: 'trashBin', additionalEquipment: [ 'stagingArea_cutoutA3', 'stagingArea_cutoutB3', 'stagingArea_cutoutC3', 'stagingArea_cutoutD3', - 'trashBin', ], modules: { 0: { @@ -185,85 +192,13 @@ describe('getNextAvailableModuleSlot', () => { type: 'temperatureModuleType', slot: 'B1', }, - }, - }) - expect(result).toStrictEqual([ - THERMOCYCLER_MODULE_TYPE, - TEMPERATURE_MODULE_TYPE, - HEATERSHAKER_MODULE_TYPE, - ]) - }) -}) -describe('getTrashSlot', () => { - it('should return the default slot A3 when there is no staging area or module in that slot', () => { - MOCK_FORM_STATE = { - ...MOCK_FORM_STATE, - additionalEquipment: ['trashBin'], - } - const result = getTrashSlot(MOCK_FORM_STATE) - expect(result).toBe(FLEX_TRASH_DEFAULT_SLOT) - }) - it('should return cutoutA1 when there is a staging area in slot A3', () => { - MOCK_FORM_STATE = { - ...MOCK_FORM_STATE, - additionalEquipment: ['stagingArea_cutoutA3'], - } - const result = getTrashSlot(MOCK_FORM_STATE) - expect(result).toBe('cutoutA1') - }) - describe('getTrashBinOptionDisabled', () => { - it('returns false when there is a trash bin already', () => { - const result = getTrashBinOptionDisabled({ - additionalEquipment: ['trashBin'], - modules: { - 0: { - model: 'heaterShakerModuleV1', - type: 'heaterShakerModuleType', - slot: 'D1', - }, - }, - }) - expect(result).toBe(false) - }) - it('returns false when there is an available slot', () => { - const result = getTrashBinOptionDisabled({ - additionalEquipment: ['trashBin'], - modules: null, - }) - expect(result).toBe(false) - }) - it('returns true when there is no available slot and trash bin is not selected yet', () => { - const result = getTrashBinOptionDisabled({ - additionalEquipment: [ - 'stagingArea_cutoutA3', - 'stagingArea_cutoutB3', - 'stagingArea_cutoutC3', - 'stagingArea_cutoutD3', - ], - modules: { - 0: { - model: 'heaterShakerModuleV1', - type: 'heaterShakerModuleType', - slot: 'D1', - }, - 1: { - model: 'temperatureModuleV2', - type: 'temperatureModuleType', - slot: 'C1', - }, - 2: { - model: 'temperatureModuleV2', - type: 'temperatureModuleType', - slot: 'B1', - }, - 3: { - model: 'temperatureModuleV2', - type: 'temperatureModuleType', - slot: 'A1', - }, + 3: { + model: 'temperatureModuleV2', + type: 'temperatureModuleType', + slot: 'A1', }, - }) - expect(result).toBe(true) + }, }) + expect(result).toBe(true) }) }) diff --git a/protocol-designer/src/components/modals/CreateFileWizard/index.tsx b/protocol-designer/src/components/modals/CreateFileWizard/index.tsx index eea2264199a..ecc37ea4b26 100644 --- a/protocol-designer/src/components/modals/CreateFileWizard/index.tsx +++ b/protocol-designer/src/components/modals/CreateFileWizard/index.tsx @@ -43,6 +43,7 @@ import { createDeckFixture, toggleIsGripperRequired, } from '../../../step-forms/actions/additionalItems' +import { createModuleWithNoSlot } from '../../../modules' import { RobotTypeTile } from './RobotTypeTile' import { MetadataTile } from './MetadataTile' import { FirstPipetteTypeTile, SecondPipetteTypeTile } from './PipetteTypeTile' @@ -229,9 +230,29 @@ export function CreateFileWizard(): JSX.Element | null { } // create modules - modules.forEach(moduleArgs => - dispatch(stepFormActions.createModule(moduleArgs)) - ) + // sort so modules with slot are created first + // then modules without a slot are generated in remaining available slots + modules.sort((a, b) => { + if (a.slot == null && b.slot != null) { + return 1 + } + if (b.slot == null && a.slot != null) { + return -1 + } + return 0 + }) + + modules.forEach(moduleArgs => { + return moduleArgs.slot != null + ? dispatch(stepFormActions.createModule(moduleArgs)) + : dispatch( + createModuleWithNoSlot({ + model: moduleArgs.model, + type: moduleArgs.type, + }) + ) + }) + // add gripper if (values.additionalEquipment.includes('gripper')) { dispatch(toggleIsGripperRequired()) @@ -240,15 +261,18 @@ export function CreateFileWizard(): JSX.Element | null { const newTiprackModels: string[] = uniq( pipettes.flatMap(pipette => pipette.tiprackDefURI) ) + const FLEX_MIDDLE_SLOTS = ['C2', 'B2', 'A2'] + const hasOt2TC = modules.find( + module => module.type === THERMOCYCLER_MODULE_TYPE + ) + const OT2_MIDDLE_SLOTS = hasOt2TC ? ['2', '5'] : ['2', '5', '8', '11'] newTiprackModels.forEach((tiprackDefURI, index) => { - const ot2Slots = index === 0 ? '2' : '5' - const flexSlots = index === 0 ? 'C2' : 'B2' dispatch( labwareIngredActions.createContainer({ slot: values.fields.robotType === FLEX_ROBOT_TYPE - ? flexSlots - : ot2Slots, + ? FLEX_MIDDLE_SLOTS[index] + : OT2_MIDDLE_SLOTS[index], labwareDefURI: tiprackDefURI, adapterUnderLabwareDefURI: values.pipettesByMount.left.pipetteName === 'p1000_96' diff --git a/protocol-designer/src/components/modals/CreateFileWizard/utils.ts b/protocol-designer/src/components/modals/CreateFileWizard/utils.ts index 2e0e8d54a72..eb3f0985c20 100644 --- a/protocol-designer/src/components/modals/CreateFileWizard/utils.ts +++ b/protocol-designer/src/components/modals/CreateFileWizard/utils.ts @@ -1,6 +1,5 @@ import { - HEATERSHAKER_MODULE_TYPE, - TEMPERATURE_MODULE_TYPE, + MAGNETIC_BLOCK_TYPE, THERMOCYCLER_MODULE_TYPE, WASTE_CHUTE_CUTOUT, } from '@opentrons/shared-data' @@ -13,41 +12,6 @@ import type { AdditionalEquipment, FormState } from './types' export const FLEX_TRASH_DEFAULT_SLOT = 'cutoutA3' -const MODULES_SLOTS_FLEX = [ - { - value: 'cutoutD1', - slot: 'D1', - }, - { - value: 'cutoutC3', - slot: 'C3', - }, - { - value: 'cutoutB1', - slot: 'B1', - }, - { - value: 'cutoutB3', - slot: 'B3', - }, - { - value: 'cutoutA3', - slot: 'A3', - }, - { - value: 'cutoutD3', - slot: 'D3', - }, - { - value: 'cutoutC1', - slot: 'C1', - }, - { - value: 'cutoutA1', - slot: 'A1', - }, -] - export const getCrashableModuleSelected = ( modules: FormModules | null, moduleType: ModuleType @@ -66,14 +30,14 @@ export const getCrashableModuleSelected = ( } export const MOVABLE_TRASH_CUTOUTS = [ - { - value: 'cutoutA1', - slot: 'A1', - }, { value: 'cutoutA3', slot: 'A3', }, + { + value: 'cutoutA1', + slot: 'A1', + }, { value: 'cutoutB1', slot: 'B1', @@ -120,102 +84,63 @@ export const getUnoccupiedStagingAreaSlots = ( return unoccupiedSlots } -export const getNextAvailableModuleSlot = ( +const TOTAL_MODULE_SLOTS = 8 + +export const getNumSlotsAvailable = ( modules: FormState['modules'], additionalEquipment: FormState['additionalEquipment'] -): string => { - const moduleSlots = - modules != null - ? Object.values(modules).flatMap(module => - module.type === THERMOCYCLER_MODULE_TYPE - ? [module.slot, 'A1'] - : module.slot - ) - : [] - const stagingAreas = additionalEquipment.filter(equipment => - equipment.includes('stagingArea') +): number => { + const additionalEquipmentLength = additionalEquipment.length + const hasTC = Object.values(modules || {}).some( + module => module.type === THERMOCYCLER_MODULE_TYPE ) - const stagingAreaCutouts = stagingAreas.map(cutout => cutout.split('_')[1]) - const hasWasteChute = additionalEquipment.find(equipment => + const hasMagneticBlock = Object.values(modules || {}).some( + module => module.type === MAGNETIC_BLOCK_TYPE + ) + let filteredModuleLength = modules != null ? Object.keys(modules).length : 0 + if (hasTC) { + filteredModuleLength = filteredModuleLength + 1 + } + if (hasMagneticBlock) { + filteredModuleLength = filteredModuleLength - 1 + } + + const hasWasteChute = additionalEquipment.some(equipment => equipment.includes('wasteChute') ) - const wasteChuteSlot = Boolean(hasWasteChute) - ? [WASTE_CHUTE_CUTOUT as string] - : [] - const trashBin = additionalEquipment.find(equipment => - equipment.includes('trashBin') + const isStagingAreaInD3 = additionalEquipment + .filter(equipment => equipment.includes('stagingArea')) + .find(stagingArea => stagingArea.split('_')[1] === 'cutoutD3') + const hasGripper = additionalEquipment.some(equipment => + equipment.includes('gripper') ) - const hasTC = - modules != null - ? Object.values(modules).some( - module => module.type === THERMOCYCLER_MODULE_TYPE - ) - : false - // removing slot(s) for the trash if spaces are limited - let removeSlotForTrash = MODULES_SLOTS_FLEX - if (trashBin != null && hasTC) { - removeSlotForTrash = MODULES_SLOTS_FLEX.slice(0, -2) - } else if (trashBin != null && !hasTC) { - removeSlotForTrash = MODULES_SLOTS_FLEX.slice(0, -1) + let filteredAdditionalEquipmentLength = additionalEquipmentLength + if (hasWasteChute && isStagingAreaInD3) { + filteredAdditionalEquipmentLength = filteredAdditionalEquipmentLength - 1 } - const unoccupiedSlot = removeSlotForTrash.find( - cutout => - !stagingAreaCutouts.includes(cutout.value) && - !moduleSlots.includes(cutout.slot) && - !wasteChuteSlot.includes(cutout.value) - ) - if (unoccupiedSlot == null) { - return '' + if (hasGripper) { + filteredAdditionalEquipmentLength = filteredAdditionalEquipmentLength - 1 } - - return unoccupiedSlot?.slot ?? '' + return ( + TOTAL_MODULE_SLOTS - + (filteredModuleLength + filteredAdditionalEquipmentLength) + ) } -interface DisabledEquipmentProps { +interface TrashOptionDisabledProps { + trashType: 'trashBin' | 'wasteChute' additionalEquipment: AdditionalEquipment[] modules: FormModules | null } -export const getDisabledEquipment = ( - props: DisabledEquipmentProps -): string[] => { - const { additionalEquipment, modules } = props - const nextAvailableSlot = getNextAvailableModuleSlot( - modules, - additionalEquipment - ) - const disabledEquipment: string[] = [] - - const moduleSlots = - modules != null - ? Object.values(modules).flatMap(module => - module.type === THERMOCYCLER_MODULE_TYPE - ? [module.slot, 'A1'] - : module.slot - ) - : [] - - if (moduleSlots.includes('A1') || moduleSlots.includes('B1')) { - disabledEquipment.push(THERMOCYCLER_MODULE_TYPE) - } - if (nextAvailableSlot === '') { - disabledEquipment.push(TEMPERATURE_MODULE_TYPE, HEATERSHAKER_MODULE_TYPE) - } - - return disabledEquipment -} - -export const getTrashBinOptionDisabled = ( - props: DisabledEquipmentProps +export const getTrashOptionDisabled = ( + props: TrashOptionDisabledProps ): boolean => { - const { additionalEquipment, modules } = props - const nextAvailableSlot = getNextAvailableModuleSlot( - modules, - additionalEquipment - ) - const hasTrashBinAlready = additionalEquipment.includes('trashBin') - return nextAvailableSlot === '' && !hasTrashBinAlready + const { additionalEquipment, modules, trashType } = props + const hasNoSlotsAvailable = + getNumSlotsAvailable(modules, additionalEquipment) === 0 + return hasNoSlotsAvailable && !additionalEquipment.includes(trashType) } export const getTrashSlot = (values: FormState): string => { @@ -241,13 +166,6 @@ export const getTrashSlot = (values: FormState): string => { ? [WASTE_CHUTE_CUTOUT as string] : [] - if ( - !cutouts.includes(FLEX_TRASH_DEFAULT_SLOT) && - !moduleSlots.includes('A3') - ) { - return FLEX_TRASH_DEFAULT_SLOT - } - const unoccupiedSlot = MOVABLE_TRASH_CUTOUTS.find( cutout => !cutouts.includes(cutout.value) && diff --git a/protocol-designer/src/components/modals/EditModulesModal/EditMultipleModulesModal.tsx b/protocol-designer/src/components/modals/EditModulesModal/EditMultipleModulesModal.tsx new file mode 100644 index 00000000000..cc31c4eb071 --- /dev/null +++ b/protocol-designer/src/components/modals/EditModulesModal/EditMultipleModulesModal.tsx @@ -0,0 +1,274 @@ +import * as React from 'react' +import { useTranslation } from 'react-i18next' +import { useSelector, useDispatch } from 'react-redux' +import { Controller, useForm, useWatch } from 'react-hook-form' +import { + BUTTON_TYPE_SUBMIT, + OutlineButton, + ModalShell, + Flex, + SPACING, + DIRECTION_ROW, + Box, + Text, + ALIGN_CENTER, + JUSTIFY_FLEX_END, + JUSTIFY_END, + DeckConfigurator, + DIRECTION_COLUMN, +} from '@opentrons/components' +import { + DeckConfiguration, + SINGLE_RIGHT_SLOT_FIXTURE, + TEMPERATURE_MODULE_CUTOUTS, + TEMPERATURE_MODULE_TYPE, + TEMPERATURE_MODULE_V2, + TEMPERATURE_MODULE_V2_FIXTURE, +} from '@opentrons/shared-data' +import { createModule, deleteModule } from '../../../step-forms/actions' +import { getLabwareOnSlot, getSlotIsEmpty } from '../../../step-forms' +import { getInitialDeckSetup } from '../../../step-forms/selectors' +import { getLabwareIsCompatible } from '../../../utils/labwareModuleCompatibility' +import { PDAlert } from '../../alerts/PDAlert' +import type { Control, ControllerRenderProps } from 'react-hook-form' +import type { CutoutId, ModuleType } from '@opentrons/shared-data' +import type { ModuleOnDeck } from '../../../step-forms' + +export interface EditMultipleModulesModalValues { + selectedAddressableAreas: string[] +} + +interface EditMultipleModulesModalComponentProps + extends EditMultipleModulesModalProps { + control: Control + moduleLocations: string[] | null +} + +const EditMultipleModulesModalComponent = ( + props: EditMultipleModulesModalComponentProps +): JSX.Element => { + const { t } = useTranslation(['button', 'alert']) + const { + onCloseClick, + allModulesOnDeck, + control, + moduleLocations, + moduleType, + } = props + const initialDeckSetup = useSelector(getInitialDeckSetup) + + const selectedSlots = useWatch({ + control, + name: 'selectedAddressableAreas', + defaultValue: moduleLocations ?? [], + }) + const occupiedCutoutIds = selectedSlots + .map(slot => { + const hasModSlot = + allModulesOnDeck.find( + module => + module.type === moduleType && slot === `cutout${module.slot}` + ) != null + const labwareOnSlot = getLabwareOnSlot(initialDeckSetup, slot) + const isLabwareCompatible = + (labwareOnSlot && + getLabwareIsCompatible(labwareOnSlot.def, moduleType)) ?? + true + const isEmpty = + (getSlotIsEmpty(initialDeckSetup, slot, true) || hasModSlot) && + isLabwareCompatible + + return { slot, isEmpty } + }) + .filter(slot => !slot.isEmpty) + const hasConflictedSlot = occupiedCutoutIds.length > 0 + const mappedModules: DeckConfiguration = + moduleLocations != null + ? moduleLocations.flatMap(location => { + return [ + { + cutoutId: location as CutoutId, + cutoutFixtureId: TEMPERATURE_MODULE_V2_FIXTURE, + }, + ] + }) + : [] + const STANDARD_EMPTY_SLOTS: DeckConfiguration = TEMPERATURE_MODULE_CUTOUTS.map( + cutoutId => ({ + cutoutId, + cutoutFixtureId: SINGLE_RIGHT_SLOT_FIXTURE, + }) + ) + + STANDARD_EMPTY_SLOTS.forEach(emptySlot => { + if ( + !mappedModules.some(({ cutoutId }) => cutoutId === emptySlot.cutoutId) + ) { + mappedModules.push(emptySlot) + } + }) + + const selectableSlots = + mappedModules.length > 0 ? mappedModules : STANDARD_EMPTY_SLOTS + const [updatedSlots, setUpdatedSlots] = React.useState( + selectableSlots + ) + const handleClickAdd = ( + cutoutId: string, + field: ControllerRenderProps< + EditMultipleModulesModalValues, + 'selectedAddressableAreas' + > + ): void => { + const modifiedSlots: DeckConfiguration = updatedSlots.map(slot => { + if (slot.cutoutId === cutoutId) { + return { + ...slot, + cutoutFixtureId: TEMPERATURE_MODULE_V2_FIXTURE, + } + } + return slot + }) + setUpdatedSlots(modifiedSlots) + const updatedSelectedSlots = [...selectedSlots, cutoutId] + field.onChange(updatedSelectedSlots) + } + + const handleClickRemove = ( + cutoutId: string, + field: ControllerRenderProps< + EditMultipleModulesModalValues, + 'selectedAddressableAreas' + > + ): void => { + const modifiedSlots: DeckConfiguration = updatedSlots.map(slot => { + if (slot.cutoutId === cutoutId) { + return { ...slot, cutoutFixtureId: SINGLE_RIGHT_SLOT_FIXTURE } + } + return slot + }) + setUpdatedSlots(modifiedSlots) + + field.onChange(selectedSlots.filter(item => item !== cutoutId)) + } + const occupiedSlots = occupiedCutoutIds.map( + occupiedCutout => occupiedCutout.slot.split('cutout')[1] + ) + const alertDescription = t( + `alert:module_placement.SLOTS_OCCUPIED.${ + occupiedSlots.length === 1 ? 'single' : 'multi' + }`, + { + slotName: occupiedSlots, + } + ) + + return ( + <> + + + + {hasConflictedSlot ? ( + + ) : null} + + + ( + handleClickAdd(cutoutId, field)} + handleClickRemove={cutoutId => handleClickRemove(cutoutId, field)} + showExpansion={false} + /> + )} + /> + + + {t('cancel')} + + {t('save')} + + + + ) +} + +export interface EditMultipleModulesModalProps { + onCloseClick: () => void + allModulesOnDeck: ModuleOnDeck[] + moduleType: ModuleType +} +export function EditMultipleModulesModal( + props: EditMultipleModulesModalProps +): JSX.Element { + const { onCloseClick, allModulesOnDeck, moduleType } = props + const { t } = useTranslation('modules') + const dispatch = useDispatch() + const { control, handleSubmit } = useForm() + const moduleLocations = Object.values(allModulesOnDeck) + .filter(module => module.type === moduleType) + .map(temp => `cutout${temp.slot}`) + + const onSaveClick = (data: EditMultipleModulesModalValues): void => { + onCloseClick() + + data.selectedAddressableAreas.forEach(aa => { + const moduleInSlot = Object.values(allModulesOnDeck).find(module => + aa.includes(module.slot) + ) + if (!moduleInSlot) { + dispatch( + createModule({ + slot: aa.split('cutout')[1], + type: TEMPERATURE_MODULE_TYPE, + model: TEMPERATURE_MODULE_V2, + }) + ) + } + }) + Object.values(allModulesOnDeck).forEach(module => { + const moduleCutout = `cutout${module.slot}` + if (!data.selectedAddressableAreas.includes(moduleCutout)) { + dispatch(deleteModule(module.id)) + } + }) + } + + return ( +
+ + + + {t('module_display_names.multipleTemperatureModuleTypes')} + + + + +
+ ) +} diff --git a/protocol-designer/src/components/modals/EditModulesModal/__tests__/EditMultipleModulesModal.test.tsx b/protocol-designer/src/components/modals/EditModulesModal/__tests__/EditMultipleModulesModal.test.tsx new file mode 100644 index 00000000000..fa01bd44ecf --- /dev/null +++ b/protocol-designer/src/components/modals/EditModulesModal/__tests__/EditMultipleModulesModal.test.tsx @@ -0,0 +1,106 @@ +import * as React from 'react' +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' +import { fireEvent, screen, cleanup } from '@testing-library/react' +import { renderWithProviders } from '../../../../__testing-utils__' +import { i18n } from '../../../../localization' +import { getInitialDeckSetup } from '../../../../step-forms/selectors' +import { getLabwareIsCompatible } from '../../../../utils/labwareModuleCompatibility' +import { + getLabwareOnSlot, + getSlotIsEmpty, + ModuleOnDeck, +} from '../../../../step-forms' +import { EditMultipleModulesModal } from '../EditMultipleModulesModal' +import type * as Components from '@opentrons/components' + +vi.mock('../../../../step-forms/selectors') +vi.mock('../../../../utils/labwareModuleCompatibility') +vi.mock('../../../../step-forms') +vi.mock('@opentrons/components', async importOriginal => { + const actual = await importOriginal() + return { + ...actual, + DeckConfigurator: vi.fn(() =>
mock deck config
), + } +}) + +const render = ( + props: React.ComponentProps +) => { + return renderWithProviders(, { + i18nInstance: i18n, + })[0] +} + +const mockTemp: ModuleOnDeck = { + id: 'temperatureId', + type: 'temperatureModuleType', + model: 'temperatureModuleV2', + slot: 'C3', + moduleState: {} as any, +} +const mockTemp2: ModuleOnDeck = { + id: 'temperatureId', + type: 'temperatureModuleType', + model: 'temperatureModuleV2', + slot: 'A1', + moduleState: {} as any, +} +const mockHS: ModuleOnDeck = { + id: 'heaterShakerId', + type: 'heaterShakerModuleType', + model: 'heaterShakerModuleV1', + moduleState: {} as any, + slot: 'A1', +} +describe('EditMultipleModulesModal', () => { + let props: React.ComponentProps + beforeEach(() => { + props = { + moduleType: 'temperatureModuleType', + onCloseClick: vi.fn(), + allModulesOnDeck: [mockTemp, mockTemp2], + } + vi.mocked(getInitialDeckSetup).mockReturnValue({ + modules: { + temperatureId: mockTemp, + temperatureId2: mockTemp2, + }, + labware: {}, + additionalEquipmentOnDeck: {}, + pipettes: {}, + }) + vi.mocked(getLabwareOnSlot).mockReturnValue(null) + vi.mocked(getSlotIsEmpty).mockReturnValue(true) + }) + afterEach(() => { + cleanup() + }) + it('renders modal and buttons with no error', () => { + vi.mocked(getLabwareIsCompatible).mockReturnValue(true) + render(props) + screen.getByText('mock deck config') + screen.getByText('Multiple Temperatures') + fireEvent.click(screen.getByRole('button', { name: 'cancel' })) + expect(props.onCloseClick).toHaveBeenCalled() + screen.getByRole('button', { name: 'save' }) + }) + it('renders modal with a cannot place module error', () => { + vi.mocked(getLabwareOnSlot).mockReturnValue({ slot: 'A1' } as any) + vi.mocked(getLabwareIsCompatible).mockReturnValue(false) + vi.mocked(getSlotIsEmpty).mockReturnValue(false) + props.allModulesOnDeck = [mockTemp, mockTemp2, mockHS] + vi.mocked(getInitialDeckSetup).mockReturnValue({ + modules: { + heaterShakerId: mockHS, + }, + labware: {}, + additionalEquipmentOnDeck: {}, + pipettes: {}, + }) + render(props) + screen.getByText('warning') + screen.getByText('Cannot place module') + screen.getByText('Multiple slots are occupied') + }) +}) diff --git a/protocol-designer/src/components/modals/FilePipettesModal/index.tsx b/protocol-designer/src/components/modals/FilePipettesModal/index.tsx index 9567e753085..9b415280ef2 100644 --- a/protocol-designer/src/components/modals/FilePipettesModal/index.tsx +++ b/protocol-designer/src/components/modals/FilePipettesModal/index.tsx @@ -24,11 +24,6 @@ import { OT2_ROBOT_TYPE, getPipetteSpecsV2, } from '@opentrons/shared-data' -import { StepChangesConfirmModal } from '../EditPipettesModal/StepChangesConfirmModal' -import { PipetteFields } from './PipetteFields' -import { CrashInfoBox } from '../../modules' -import styles from './FilePipettesModal.module.css' -import modalStyles from '../modal.module.css' import { actions as stepFormActions, selectors as stepFormSelectors, @@ -42,14 +37,29 @@ import { INITIAL_DECK_SETUP_STEP_ID } from '../../../constants' import { NewProtocolFields } from '../../../load-file' import { getRobotType } from '../../../file-data/selectors' import { uuid } from '../../../utils' +import { getLabwareEntities } from '../../../step-forms/selectors' +import { + createContainer, + deleteContainer, +} from '../../../labware-ingred/actions' import { actions as steplistActions } from '../../../steplist' import { selectors as featureFlagSelectors } from '../../../feature-flags' +import { CrashInfoBox } from '../../modules' import { getCrashableModuleSelected } from '../CreateFileWizard/utils' +import { adapter96ChannelDefUri } from '../CreateFileWizard' +import { StepChangesConfirmModal } from '../EditPipettesModal/StepChangesConfirmModal' +import { PipetteFields } from './PipetteFields' +import type { + LabwareEntities, + NormalizedPipette, +} from '@opentrons/step-generation' import type { DeckSlot, ThunkDispatch } from '../../../types' -import type { NormalizedPipette } from '@opentrons/step-generation' import type { StepIdType } from '../../../form-types' +import styles from './FilePipettesModal.module.css' +import modalStyles from '../modal.module.css' + export type PipetteFieldsData = Omit< PipetteOnDeck, 'id' | 'spec' | 'tiprackLabwareDef' @@ -124,6 +134,7 @@ const validationSchema: any = Yup.object().shape({ }) const makeUpdatePipettes = ( + labwareEntities: LabwareEntities, prevPipettes: { [pipetteId: string]: PipetteOnDeck }, orderedStepIds: StepIdType[], dispatch: ThunkDispatch, @@ -159,6 +170,38 @@ const makeUpdatePipettes = ( } } }) + const newTiprackUris = new Set( + newPipetteArray.flatMap(pipette => pipette.tiprackDefURI) + ) + const previousTiprackLabwares = Object.values(labwareEntities).filter( + labware => labware.def.parameters.isTiprack + ) + + const previousTiprackUris = new Set( + previousTiprackLabwares.map(labware => labware.labwareDefURI) + ) + + // Find tipracks to delete (old tipracks not in new pipettes) + previousTiprackLabwares + .filter(labware => !newTiprackUris.has(labware.labwareDefURI)) + .forEach(labware => dispatch(deleteContainer({ labwareId: labware.id }))) + + // Create new tipracks that are not in previous tiprackURIs + newTiprackUris.forEach(tiprackDefUri => { + if (!previousTiprackUris.has(tiprackDefUri)) { + const adapterUnderLabwareDefURI = newPipetteArray.some( + pipette => pipette.name === 'p1000_96' + ) + ? adapter96ChannelDefUri + : undefined + dispatch( + createContainer({ + labwareDefURI: tiprackDefUri, + adapterUnderLabwareDefURI, + }) + ) + } + }) dispatch( stepFormActions.createPipettes( @@ -275,6 +318,7 @@ export const FilePipettesModal = (props: Props): JSX.Element => { const { t } = useTranslation(['modal', 'button', 'form']) const robotType = useSelector(getRobotType) const dispatch = useDispatch() + const labwareEntities = useSelector(getLabwareEntities) const initialPipettes = useSelector( stepFormSelectors.getPipettesForEditPipetteForm ) @@ -295,6 +339,7 @@ export const FilePipettesModal = (props: Props): JSX.Element => { modules: ModuleCreationArgs[] pipettes: PipetteFieldsData[] }) => void = makeUpdatePipettes( + labwareEntities, prevPipettes, orderedStepIds, dispatch, diff --git a/protocol-designer/src/components/modals/FileUploadMessageModal/modalContents.tsx b/protocol-designer/src/components/modals/FileUploadMessageModal/modalContents.tsx index f09052a5c5f..8f7af3bc68f 100644 --- a/protocol-designer/src/components/modals/FileUploadMessageModal/modalContents.tsx +++ b/protocol-designer/src/components/modals/FileUploadMessageModal/modalContents.tsx @@ -96,6 +96,23 @@ export const getToV8MigrationMessage = (props: ModalProps): ModalContents => { } } +export const getToV8_1MigrationMessage = (props: ModalProps): ModalContents => { + const { t } = props + + return { + title: t('migrations.header', { pd: PD }), + body: ( +
+

+

{t('migrations.toV8_1Migration.body1')}

+

+

{t('migrations.toV8_1Migration.body2')}

+

{t('migrations.toV8_1Migration.body3')}

+
+ ), + } +} + export const getToV3MigrationMessage = (props: ModalProps): ModalContents => { const { t } = props @@ -152,9 +169,12 @@ export const getMigrationMessage = ( ) { return getNoBehaviorChangeMessage({ t }) } - if (migrationsRan.includes('8.0.0')) { + if (migrationsRan.includes('8.1.0')) { + return getToV8_1MigrationMessage({ t }) + } else if (migrationsRan.includes('8.0.0')) { return getToV8MigrationMessage({ t }) } + return getGenericDidMigrateMessage({ t }) } diff --git a/protocol-designer/src/components/modules/EditModulesCard.tsx b/protocol-designer/src/components/modules/EditModulesCard.tsx index 40df5ef14a2..27dcc233ede 100644 --- a/protocol-designer/src/components/modules/EditModulesCard.tsx +++ b/protocol-designer/src/components/modules/EditModulesCard.tsx @@ -27,10 +27,12 @@ import { CrashInfoBox } from './CrashInfoBox' import { ModuleRow } from './ModuleRow' import { AdditionalItemsRow } from './AdditionalItemsRow' import { isModuleWithCollisionIssue } from './utils' -import styles from './styles.module.css' -import { AdditionalEquipmentEntity } from '@opentrons/step-generation' import { StagingAreasRow } from './StagingAreasRow' +import { MultipleModulesRow } from './MultipleModulesRow' + +import type { AdditionalEquipmentEntity } from '@opentrons/step-generation' +import styles from './styles.module.css' export interface Props { modules: ModulesForEditModulesCard openEditModuleModal: (moduleType: ModuleType, moduleId?: string) => void @@ -38,6 +40,7 @@ export interface Props { export function EditModulesCard(props: Props): JSX.Element { const { modules, openEditModuleModal } = props + const pipettesByMount = useSelector( stepFormSelectors.getPipettesForEditPipetteForm ) @@ -67,10 +70,10 @@ export function EditModulesCard(props: Props): JSX.Element { ) const hasCrashableMagneticModule = magneticModuleOnDeck && - isModuleWithCollisionIssue(magneticModuleOnDeck.model) + isModuleWithCollisionIssue(magneticModuleOnDeck[0].model) const hasCrashableTempModule = temperatureModuleOnDeck && - isModuleWithCollisionIssue(temperatureModuleOnDeck.model) + isModuleWithCollisionIssue(temperatureModuleOnDeck[0].model) const isHeaterShakerOnDeck = Boolean(heaterShakerOnDeck) const showTempPipetteCollisons = @@ -130,22 +133,33 @@ export function EditModulesCard(props: Props): JSX.Element { ) : null} {SUPPORTED_MODULE_TYPES_FILTERED.map((moduleType, i) => { const moduleData = modules[moduleType] - if (moduleData) { + if (moduleData != null && moduleData.length === 1) { return ( ) + } else if (moduleData != null && moduleData.length > 1) { + return ( + + ) } else { return ( ) diff --git a/protocol-designer/src/components/modules/MultipleModulesRow.tsx b/protocol-designer/src/components/modules/MultipleModulesRow.tsx new file mode 100644 index 00000000000..fa6ffb20c76 --- /dev/null +++ b/protocol-designer/src/components/modules/MultipleModulesRow.tsx @@ -0,0 +1,123 @@ +import * as React from 'react' +import { useTranslation } from 'react-i18next' +import { useDispatch } from 'react-redux' +import { + LabeledValue, + OutlineButton, + ModuleIcon, + C_DARK_GRAY, + SPACING, +} from '@opentrons/components' +import { actions as stepFormActions } from '../../step-forms' +import { DEFAULT_MODEL_FOR_MODULE_TYPE } from '../../constants' +import { ModuleDiagram } from './ModuleDiagram' +import { FlexSlotMap } from './FlexSlotMap' +import type { ModuleModel, ModuleType } from '@opentrons/shared-data' +import type { ModuleOnDeck } from '../../step-forms' + +import styles from './styles.module.css' + +interface MultipleModulesRowProps { + moduleType: ModuleType + openEditModuleModal: (moduleType: ModuleType, moduleId?: string) => void + moduleOnDeckType?: ModuleType + moduleOnDeckModel?: ModuleModel + moduleOnDeck?: ModuleOnDeck[] +} + +export function MultipleModulesRow( + props: MultipleModulesRowProps +): JSX.Element { + const { + moduleOnDeck, + openEditModuleModal, + moduleOnDeckModel, + moduleOnDeckType, + moduleType, + } = props + const { t } = useTranslation(['modules', 'shared']) + const dispatch = useDispatch() + + const type: ModuleType = moduleOnDeckType ?? moduleType + const occupiedSlots = moduleOnDeck?.map(module => module.slot) ?? [] + const occupiedSlotsDisplayName = ( + moduleOnDeck?.map(module => module.slot) ?? [] + ).join(', ') + + const setCurrentModule = (moduleType: ModuleType, moduleId?: string) => () => + openEditModuleModal(moduleType, moduleId) + + const addRemoveText = moduleOnDeck ? t('shared:remove') : t('shared:add') + + const handleAddOrRemove = (): void => { + if (moduleOnDeck != null) { + moduleOnDeck.forEach(module => { + dispatch(stepFormActions.deleteModule(module.id)) + }) + } else { + setCurrentModule(type) + } + } + const handleEditModule = + moduleOnDeck && setCurrentModule(type, moduleOnDeck[0].id) + + return ( +
+

+ + {t( + `module_display_names.${ + occupiedSlots.length > 1 ? 'multipleTemperatureModuleTypes' : type + }` + )} +

+
+
+ +
+
+ {moduleOnDeckModel && ( + + )} +
+
+ {occupiedSlots.length > 0 ? ( + + ) : null} +
+
+ {occupiedSlots.length > 0 ? ( + + ) : null} +
+
+ {moduleOnDeck != null ? ( + + {t('shared:edit')} + + ) : null} + + {addRemoveText} + +
+
+
+ ) +} diff --git a/protocol-designer/src/components/modules/TrashModal.tsx b/protocol-designer/src/components/modules/TrashModal.tsx index d8fffc264ee..dad0f799213 100644 --- a/protocol-designer/src/components/modules/TrashModal.tsx +++ b/protocol-designer/src/components/modules/TrashModal.tsx @@ -87,11 +87,14 @@ const TrashModalComponent = (props: TrashModalComponentProps): JSX.Element => { name: 'selectedSlot', defaultValue: defaultValue, }) - const isSlotEmpty = getSlotIsEmpty( - initialDeckSetup, - selectedSlot, - trashName === 'trashBin' - ) + const hasTrashAlreadyInSlot = Object.values( + initialDeckSetup.additionalEquipmentOnDeck + ).find(aE => aE.name === 'trashBin' && aE.location === selectedSlot) + + const isSlotEmpty = + getSlotIsEmpty(initialDeckSetup, selectedSlot, trashName === 'trashBin') || + hasTrashAlreadyInSlot + const slotFromCutout = selectedSlot.replace('cutout', '') const flexDeck = getDeckDefFromRobotType(FLEX_ROBOT_TYPE) diff --git a/protocol-designer/src/components/modules/__tests__/MultipleModuleRow.test.tsx b/protocol-designer/src/components/modules/__tests__/MultipleModuleRow.test.tsx new file mode 100644 index 00000000000..9c8e0027327 --- /dev/null +++ b/protocol-designer/src/components/modules/__tests__/MultipleModuleRow.test.tsx @@ -0,0 +1,67 @@ +import * as React from 'react' +import { describe, it, expect, vi, beforeEach } from 'vitest' +import { fireEvent, screen } from '@testing-library/react' + +import { i18n } from '../../../localization' +import { renderWithProviders } from '../../../__testing-utils__' +import { MultipleModulesRow } from '../MultipleModulesRow' +import { + TEMPERATURE_MODULE_TYPE, + TEMPERATURE_MODULE_V2, +} from '@opentrons/shared-data' +import { FlexSlotMap } from '../FlexSlotMap' +import { deleteModule } from '../../../step-forms/actions' +import type { ModuleOnDeck } from '../../../step-forms' + +vi.mock('../../../step-forms/actions') +vi.mock('../FlexSlotMap') +const render = (props: React.ComponentProps) => { + return renderWithProviders(, { + i18nInstance: i18n, + })[0] +} + +const mockTemp: ModuleOnDeck = { + id: 'temperatureId', + type: 'temperatureModuleType', + model: 'temperatureModuleV2', + slot: 'C3', + moduleState: {} as any, +} +const mockTemp2: ModuleOnDeck = { + id: 'temperatureId', + type: 'temperatureModuleType', + model: 'temperatureModuleV2', + slot: 'A1', + moduleState: {} as any, +} + +describe('MultipleModuleRow', () => { + let props: React.ComponentProps + beforeEach(() => { + props = { + moduleType: TEMPERATURE_MODULE_TYPE, + openEditModuleModal: vi.fn(), + moduleOnDeckType: TEMPERATURE_MODULE_TYPE, + moduleOnDeckModel: TEMPERATURE_MODULE_V2, + moduleOnDeck: [mockTemp, mockTemp2], + } + vi.mocked(FlexSlotMap).mockReturnValue(
mock FlexSlotMap
) + }) + it('renders 2 modules in the row with text and buttons', () => { + render(props) + screen.getByText('Multiple Temperatures') + screen.getByText('Position:') + screen.getByText('C3, A1') + screen.getByText('mock FlexSlotMap') + fireEvent.click(screen.getByText('edit')) + expect(props.openEditModuleModal).toHaveBeenCalled() + fireEvent.click(screen.getByText('remove')) + expect(vi.mocked(deleteModule)).toHaveBeenCalled() + }) + it('renders no modules', () => { + props.moduleOnDeck = undefined + render(props) + screen.getByText('add') + }) +}) diff --git a/protocol-designer/src/constants.ts b/protocol-designer/src/constants.ts index b92192565c2..14308884b81 100644 --- a/protocol-designer/src/constants.ts +++ b/protocol-designer/src/constants.ts @@ -58,7 +58,7 @@ export const INITIAL_DECK_SETUP_STEP_ID = '__INITIAL_DECK_SETUP_STEP__' export const DEFAULT_CHANGE_TIP_OPTION: 'always' = 'always' // TODO: Ian 2019-06-13 don't keep these as hard-coded static values (see #3587) export const DEFAULT_MM_FROM_BOTTOM_ASPIRATE = 1 -export const DEFAULT_MM_FROM_BOTTOM_DISPENSE = 0.5 +export const DEFAULT_MM_FROM_BOTTOM_DISPENSE = 1 // NOTE: in the negative Z direction, to go down from top export const DEFAULT_MM_TOUCH_TIP_OFFSET_FROM_TOP = -1 export const DEFAULT_MM_BLOWOUT_OFFSET_FROM_TOP = 0 diff --git a/protocol-designer/src/containers/__tests__/ConnectedStepItem.test.tsx b/protocol-designer/src/containers/__tests__/ConnectedStepItem.test.tsx index cce62e03887..4156202796b 100644 --- a/protocol-designer/src/containers/__tests__/ConnectedStepItem.test.tsx +++ b/protocol-designer/src/containers/__tests__/ConnectedStepItem.test.tsx @@ -1,7 +1,8 @@ import * as React from 'react' import { describe, it, beforeEach, vi } from 'vitest' import { screen } from '@testing-library/react' -import { fixture96Plate } from '@opentrons/shared-data' +import '@testing-library/jest-dom/vitest' +import { fixture96Plate, fixtureTiprack1000ul } from '@opentrons/shared-data' import { renderWithProviders } from '../../__testing-utils__' import { i18n } from '../../localization' import { @@ -49,8 +50,9 @@ const heaterShakerStepId = 'hsStepId' const thermocyclerStepId = 'tcStepId' const temperatureStepId = 'tempStepId' const moveLabwareStepId = 'moveLabwareId' +const mixStepId = 'mixStepId' +const moveLiquidStepId = 'moveLiquidStepId' -// TODO(jr, 4/8/24): add test coverage for mix and moveLiquid!!! describe('ConnectedStepItem', () => { let props: React.ComponentProps beforeEach(() => { @@ -89,6 +91,14 @@ describe('ConnectedStepItem', () => { stepType: 'moveLabware', id: moveLabwareStepId, }, + [mixStepId]: { + stepType: 'mix', + id: mixStepId, + }, + [moveLiquidStepId]: { + stepType: 'moveLiquid', + id: moveLiquidStepId, + }, }) vi.mocked(getArgsAndErrorsByStepId).mockReturnValue({ [pauseStepId]: { @@ -115,6 +125,14 @@ describe('ConnectedStepItem', () => { errors: false, stepArgs: null, }, + [mixStepId]: { + errors: false, + stepArgs: null, + }, + [moveLiquidStepId]: { + errors: false, + stepArgs: null, + }, }) vi.mocked(getErrorStepId).mockReturnValue(null) vi.mocked(getHasTimelineWarningsPerStep).mockReturnValue({ @@ -124,6 +142,8 @@ describe('ConnectedStepItem', () => { [thermocyclerStepId]: false, [temperatureStepId]: false, [moveLabwareStepId]: false, + [mixStepId]: false, + [moveLiquidStepId]: false, }) vi.mocked(getHasFormLevelWarningsPerStep).mockReturnValue({ [pauseStepId]: false, @@ -132,6 +152,8 @@ describe('ConnectedStepItem', () => { [thermocyclerStepId]: false, [temperatureStepId]: false, [moveLabwareStepId]: false, + [mixStepId]: false, + [moveLiquidStepId]: false, }) vi.mocked(getInitialDeckSetup).mockReturnValue({ pipettes: {}, @@ -179,6 +201,12 @@ describe('ConnectedStepItem', () => { slot: 'A2', def: fixture96Plate as LabwareDefinition2, }, + tipId: { + id: 'tipId', + labwareDefURI: `opentrons/${fixtureTiprack1000ul.parameters.loadName}/1`, + slot: 'D2', + def: fixtureTiprack1000ul as LabwareDefinition2, + }, }, }) vi.mocked(getCollapsedSteps).mockReturnValue({ @@ -188,6 +216,8 @@ describe('ConnectedStepItem', () => { [thermocyclerStepId]: true, [temperatureStepId]: true, [moveLabwareStepId]: true, + [mixStepId]: true, + [moveLiquidStepId]: true, }) vi.mocked(getHoveredSubstep).mockReturnValue(null) vi.mocked(getSelectedStepId).mockReturnValue(pauseStepId) @@ -198,6 +228,8 @@ describe('ConnectedStepItem', () => { thermocyclerStepId, moveLabwareStepId, temperatureStepId, + mixStepId, + moveLiquidStepId, ]) vi.mocked(getMultiSelectItemIds).mockReturnValue(null) vi.mocked(getMultiSelectLastSelected).mockReturnValue(null) @@ -260,6 +292,32 @@ describe('ConnectedStepItem', () => { newLocation: { slotName: 'B2' }, }, }, + [mixStepId]: { + substepType: 'sourceDest', + multichannel: false, + commandCreatorFnName: 'mix', + parentStepId: mixStepId, + rows: [ + { + activeTips: null, + }, + ], + }, + [moveLiquidStepId]: { + substepType: 'sourceDest', + multichannel: false, + commandCreatorFnName: 'transfer', + parentStepId: moveLiquidStepId, + rows: [ + { + activeTips: { labwareId: 'tipId', wellName: 'A1' }, + substepIndex: 2, + source: { well: 'A1', preIngreds: {}, postIngreds: {} }, + dest: { well: 'A1', preIngreds: {}, postIngreds: {} }, + volume: 50, + }, + ], + }, }) vi.mocked(labwareIngredSelectors.getLiquidNamesById).mockReturnValue({}) vi.mocked(getLabwareNicknamesById).mockReturnValue({}) @@ -286,6 +344,8 @@ describe('ConnectedStepItem', () => { [thermocyclerStepId]: true, [temperatureStepId]: true, [moveLabwareStepId]: true, + [mixStepId]: true, + [moveLiquidStepId]: true, }) vi.mocked(getSelectedStepId).mockReturnValue(magnetStepId) props.stepId = magnetStepId @@ -303,6 +363,8 @@ describe('ConnectedStepItem', () => { [thermocyclerStepId]: true, [temperatureStepId]: true, [moveLabwareStepId]: true, + [mixStepId]: true, + [moveLiquidStepId]: true, }) vi.mocked(getSelectedStepId).mockReturnValue(heaterShakerStepId) props.stepId = heaterShakerStepId @@ -326,6 +388,8 @@ describe('ConnectedStepItem', () => { [thermocyclerStepId]: false, [temperatureStepId]: true, [moveLabwareStepId]: true, + [mixStepId]: true, + [moveLiquidStepId]: true, }) vi.mocked(getSelectedStepId).mockReturnValue(thermocyclerStepId) props.stepId = thermocyclerStepId @@ -348,6 +412,8 @@ describe('ConnectedStepItem', () => { [thermocyclerStepId]: true, [temperatureStepId]: false, [moveLabwareStepId]: true, + [mixStepId]: true, + [moveLiquidStepId]: true, }) vi.mocked(getSelectedStepId).mockReturnValue(temperatureStepId) props.stepId = temperatureStepId @@ -367,6 +433,8 @@ describe('ConnectedStepItem', () => { [thermocyclerStepId]: true, [temperatureStepId]: true, [moveLabwareStepId]: false, + [mixStepId]: true, + [moveLiquidStepId]: true, }) vi.mocked(getSelectedStepId).mockReturnValue(moveLabwareStepId) props.stepId = moveLabwareStepId @@ -376,4 +444,68 @@ describe('ConnectedStepItem', () => { screen.getByText('labware') screen.getByText('new location') }) + it('renders an expanded step for mix', () => { + vi.mocked(getCollapsedSteps).mockReturnValue({ + [pauseStepId]: true, + [magnetStepId]: true, + [heaterShakerStepId]: true, + [thermocyclerStepId]: true, + [temperatureStepId]: true, + [moveLabwareStepId]: true, + [mixStepId]: false, + [moveLiquidStepId]: true, + }) + vi.mocked(getSelectedStepId).mockReturnValue(mixStepId) + props.stepId = mixStepId + render(props) + screen.getByText('2. mix') + screen.getByText('uL') + screen.getByText('μL') + }) + it('renders an expanded step for move liquid (transfer)', () => { + vi.mocked(getCollapsedSteps).mockReturnValue({ + [pauseStepId]: true, + [magnetStepId]: true, + [heaterShakerStepId]: true, + [thermocyclerStepId]: true, + [temperatureStepId]: true, + [moveLabwareStepId]: true, + [mixStepId]: true, + [moveLiquidStepId]: false, + }) + vi.mocked(getSelectedStepId).mockReturnValue(moveLiquidStepId) + props.stepId = moveLiquidStepId + render(props) + screen.getByText('2. transfer') + screen.getByText('ASPIRATE') + screen.getByText('DISPENSE') + screen.getAllByText('A1') + screen.getByText('50 μL') + }) + it('renders a timeline warning icon for move liquid', () => { + vi.mocked(getHasTimelineWarningsPerStep).mockReturnValue({ + [pauseStepId]: false, + [magnetStepId]: false, + [heaterShakerStepId]: false, + [thermocyclerStepId]: false, + [temperatureStepId]: false, + [moveLabwareStepId]: false, + [mixStepId]: false, + [moveLiquidStepId]: true, + }) + vi.mocked(getCollapsedSteps).mockReturnValue({ + [pauseStepId]: true, + [magnetStepId]: true, + [heaterShakerStepId]: true, + [thermocyclerStepId]: true, + [temperatureStepId]: true, + [moveLabwareStepId]: true, + [mixStepId]: true, + [moveLiquidStepId]: false, + }) + vi.mocked(getSelectedStepId).mockReturnValue(moveLiquidStepId) + props.stepId = moveLiquidStepId + render(props) + screen.getByTestId('TitledStepList_icon_alert-circle') + }) }) diff --git a/protocol-designer/src/feature-flags/reducers.ts b/protocol-designer/src/feature-flags/reducers.ts index 0fb93e30a8f..bddaa38c628 100644 --- a/protocol-designer/src/feature-flags/reducers.ts +++ b/protocol-designer/src/feature-flags/reducers.ts @@ -21,8 +21,6 @@ const initialFlags: Flags = { process.env.OT_PD_DISABLE_MODULE_RESTRICTIONS === '1' || false, OT_PD_ALLOW_ALL_TIPRACKS: process.env.OT_PD_ALLOW_ALL_TIPRACKS === '1' || false, - OT_PD_ENABLE_MULTI_TIP: process.env.OT_PD_ENABLE_MULTI_TIP === '1' || false, - OT_PD_ENABLE_MOAM: process.env.OT_PD_ENABLE_MOAM === '1' || false, } // @ts-expect-error(sa, 2021-6-10): cannot use string literals as action type // TODO IMMEDIATELY: refactor this to the old fashioned way if we cannot have type safety: https://github.com/redux-utilities/redux-actions/issues/282#issuecomment-595163081 diff --git a/protocol-designer/src/feature-flags/selectors.ts b/protocol-designer/src/feature-flags/selectors.ts index 49aaa937cb4..35f69dd70da 100644 --- a/protocol-designer/src/feature-flags/selectors.ts +++ b/protocol-designer/src/feature-flags/selectors.ts @@ -19,11 +19,3 @@ export const getAllowAllTipracks: Selector = createSelector( getFeatureFlagData, flags => flags.OT_PD_ALLOW_ALL_TIPRACKS ?? false ) -export const getEnableMultiTip: Selector = createSelector( - getFeatureFlagData, - flags => flags.OT_PD_ENABLE_MULTI_TIP ?? false -) -export const getEnableMoam: Selector = createSelector( - getFeatureFlagData, - flags => flags.OT_PD_ENABLE_MOAM ?? false -) diff --git a/protocol-designer/src/feature-flags/types.ts b/protocol-designer/src/feature-flags/types.ts index 99b4b76b1f6..7a9c04b5af9 100644 --- a/protocol-designer/src/feature-flags/types.ts +++ b/protocol-designer/src/feature-flags/types.ts @@ -22,14 +22,14 @@ export const DEPRECATED_FLAGS = [ 'OT_PD_ENABLE_OT_3', 'OT_PD_ALLOW_96_CHANNEL', 'OT_PD_ENABLE_FLEX_DECK_MODIFICATION', + 'OT_PD_ENABLE_MULTI_TIP', + 'OT_PD_ENABLE_MOAM', ] // union of feature flag string constant IDs export type FlagTypes = | 'PRERELEASE_MODE' | 'OT_PD_DISABLE_MODULE_RESTRICTIONS' | 'OT_PD_ALLOW_ALL_TIPRACKS' - | 'OT_PD_ENABLE_MULTI_TIP' - | 'OT_PD_ENABLE_MOAM' // flags that are not in this list only show in prerelease mode export const userFacingFlags: FlagTypes[] = [ 'OT_PD_DISABLE_MODULE_RESTRICTIONS', diff --git a/protocol-designer/src/form-types.ts b/protocol-designer/src/form-types.ts index f369844ad37..1e12911f1ac 100644 --- a/protocol-designer/src/form-types.ts +++ b/protocol-designer/src/form-types.ts @@ -233,6 +233,7 @@ export interface HydratedMoveLiquidFormData { dispense_x_position?: number | null dispense_y_position?: number | null blowout_z_offset?: number | null + blowout_flowRate?: number | null } } @@ -277,6 +278,7 @@ export interface HydratedMixFormDataLegacy { mix_x_position?: number | null mix_y_position?: number | null blowout_z_offset?: number | null + blowout_flowRate?: number | null } export type MagnetAction = 'engage' | 'disengage' export type HydratedMagnetFormData = AnnotationFields & { diff --git a/protocol-designer/src/load-file/migration/8_1_0.ts b/protocol-designer/src/load-file/migration/8_1_0.ts index 755ef2a3ed2..1733316120d 100644 --- a/protocol-designer/src/load-file/migration/8_1_0.ts +++ b/protocol-designer/src/load-file/migration/8_1_0.ts @@ -1,6 +1,9 @@ +import { getDefaultBlowoutFlowRate } from './utils/getDefaultBlowoutFlowRate' import type { + LoadPipetteCreateCommand, LoadLabwareCreateCommand, ProtocolFile, + PipetteName, } from '@opentrons/shared-data' import type { DesignerApplicationData } from './utils/getLoadLiquidCommands' @@ -43,10 +46,17 @@ export const migrateFile = ( {} ) + const pipetteTiprackAssignments = + designerApplication.data?.pipetteTiprackAssignments + const loadLabwareCommands = commands.filter( (command): command is LoadLabwareCreateCommand => command.commandType === 'loadLabware' ) + const loadPipetteCommands = commands.filter( + (command): command is LoadPipetteCreateCommand => + command.commandType === 'loadPipette' + ) const savedStepForms = designerApplication.data ?.savedStepForms as DesignerApplicationData['savedStepForms'] @@ -64,9 +74,9 @@ export const migrateFile = ( `expected to find tiprack definition with labwareDefintionURI ${tipRackUri} but could not` ) } - const tiprackIds = loadLabwareCommands - .filter(command => command.params.loadName === tiprackLoadName) - .map(command => command.params.labwareId) + const tiprackLoadCommands = loadLabwareCommands.filter( + command => command.params.loadName === tiprackLoadName + ) const xyKeys = item.stepType === 'mix' ? { mix_x_position: 0, mix_y_position: 0 } @@ -76,10 +86,44 @@ export const migrateFile = ( dispense_x_position: 0, dispense_y_position: 0, } + const matchingTiprackCommand = tiprackLoadCommands.find( + command => command.params.labwareId === item.tipRack + ) + if (matchingTiprackCommand == null) { + console.error( + `expected to find a tiprack loadname from tiprack ${item.tipRack} but could not ` + ) + } + const matchingTiprackURI = + matchingTiprackCommand != null + ? `${matchingTiprackCommand.params.namespace}/${matchingTiprackCommand.params.loadName}/${matchingTiprackCommand.params.version}` + : null + const tipLength = + matchingTiprackURI != null + ? labwareDefinitions[matchingTiprackURI].parameters.tipLength ?? 0 + : 0 + const pipetteName = loadPipetteCommands.find( + pipette => pipette.params.pipetteId === item.pipette + )?.params.pipetteName + + const defaultBlowOutFlowRate = getDefaultBlowoutFlowRate( + pipetteName as PipetteName, + item.volume, + tipLength + ) + + let blowoutFlowRate: number | null = defaultBlowOutFlowRate + if (item.blowout_checkbox === false) { + blowoutFlowRate = null + } + + const tipRackDefURI = pipetteTiprackAssignments[item.pipette] + acc[item.id] = { ...item, + blowout_flowRate: blowoutFlowRate, blowout_z_offset: 0, - tipRack: tiprackIds[0], + tipRack: tipRackDefURI, ...xyKeys, } return acc diff --git a/protocol-designer/src/load-file/migration/__tests__/__snapshots__/3_0_0.test.ts.snap b/protocol-designer/src/load-file/migration/__tests__/__snapshots__/3_0_0.test.ts.snap index 5fe841bb055..d0eeb3dde9e 100644 --- a/protocol-designer/src/load-file/migration/__tests__/__snapshots__/3_0_0.test.ts.snap +++ b/protocol-designer/src/load-file/migration/__tests__/__snapshots__/3_0_0.test.ts.snap @@ -297,301 +297,3 @@ exports[`migrate to 3.0.0 > snapshot test 1`] = ` "schemaVersion": 3, } `; - -exports[`migrate to 3.0.0 snapshot test 1`] = ` -Object { - "commands": Array [], - "designerApplication": Object { - "data": Object { - "dismissedWarnings": Object { - "form": Object {}, - "timeline": Object {}, - }, - "ingredLocations": Object { - "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well": Object { - "A1": Object { - "0": Object { - "volume": 121, - }, - }, - "B1": Object { - "0": Object { - "volume": 121, - }, - }, - "C1": Object { - "0": Object { - "volume": 121, - }, - }, - "D1": Object { - "0": Object { - "volume": 121, - }, - }, - "E1": Object { - "0": Object { - "volume": 121, - }, - }, - "F1": Object { - "1": Object { - "volume": 44, - }, - }, - "G1": Object { - "1": Object { - "volume": 44, - }, - }, - "H1": Object { - "1": Object { - "volume": 44, - }, - }, - }, - }, - "ingredients": Object { - "0": Object { - "description": null, - "liquidGroupId": "0", - "name": "samples", - "serialize": false, - }, - "1": Object { - "description": null, - "liquidGroupId": "1", - "name": "dna", - "serialize": false, - }, - }, - "orderedStepIds": Array [ - "e7d36200-92a5-11e9-ac62-1b173f839d9e", - "18113c80-92a6-11e9-ac62-1b173f839d9e", - "2e622080-92a6-11e9-ac62-1b173f839d9e", - ], - "pipetteTiprackAssignments": Object { - "c6f45030-92a5-11e9-ac62-1b173f839d9e": "fixture/fixture_regular_example_1/1", - "c6f47740-92a5-11e9-ac62-1b173f839d9e": "fixture/fixture_regular_example_1/1", - }, - "savedStepForms": Object { - "18113c80-92a6-11e9-ac62-1b173f839d9e": Object { - "aspirate_flowRate": 8, - "blowout_checkbox": true, - "blowout_location": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", - "changeTip": "always", - "dispense_flowRate": 7, - "id": "18113c80-92a6-11e9-ac62-1b173f839d9e", - "labware": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", - "mix_mmFromBottom": 0.5, - "mix_touchTip_checkbox": true, - "mix_touchTip_mmFromBottom": 30.5, - "mix_wellOrder_first": "t2b", - "mix_wellOrder_second": "l2r", - "pipette": "c6f45030-92a5-11e9-ac62-1b173f839d9e", - "stepDetails": "", - "stepName": "mix", - "stepType": "mix", - "times": 3, - "volume": "5.5", - "wells": Array [ - "F1", - ], - }, - "2e622080-92a6-11e9-ac62-1b173f839d9e": Object { - "id": "2e622080-92a6-11e9-ac62-1b173f839d9e", - "pauseForAmountOfTime": "true", - "pauseHour": 1, - "pauseMessage": "Delay plz", - "pauseMinute": 2, - "pauseSecond": 3, - "stepDetails": "", - "stepName": "pause", - "stepType": "pause", - }, - "__INITIAL_DECK_SETUP_STEP__": Object { - "id": "__INITIAL_DECK_SETUP_STEP__", - "labwareLocationUpdate": Object { - "c6f4ec70-92a5-11e9-ac62-1b173f839d9e:tiprack-10ul": "1", - "c6f51380-92a5-11e9-ac62-1b173f839d9e:tiprack-200ul": "2", - "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well": "10", - "trashId": "12", - }, - "pipetteLocationUpdate": Object { - "c6f45030-92a5-11e9-ac62-1b173f839d9e": "left", - "c6f47740-92a5-11e9-ac62-1b173f839d9e": "right", - }, - "stepType": "manualIntervention", - }, - "e7d36200-92a5-11e9-ac62-1b173f839d9e": Object { - "aspirate_flowRate": 0.6, - "aspirate_labware": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", - "aspirate_mix_checkbox": true, - "aspirate_mix_times": 3, - "aspirate_mix_volume": "2", - "aspirate_mmFromBottom": 1, - "aspirate_touchTip_checkbox": true, - "aspirate_touchTip_mmFromBottom": 28.5, - "aspirate_wellOrder_first": "t2b", - "aspirate_wellOrder_second": "l2r", - "aspirate_wells": Array [ - "A1", - ], - "aspirate_wells_grouped": false, - "blowout_checkbox": true, - "blowout_location": "trashId", - "changeTip": "always", - "dispense_labware": "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well", - "dispense_mix_checkbox": true, - "dispense_mix_times": 2, - "dispense_mix_volume": "3", - "dispense_mmFromBottom": 2.5, - "dispense_touchTip_checkbox": true, - "dispense_wellOrder_first": "b2t", - "dispense_wellOrder_second": "r2l", - "dispense_wells": Array [ - "C6", - "D6", - "E6", - "C7", - "D7", - "E7", - "C8", - "D8", - "E8", - ], - "disposalVolume_checkbox": true, - "disposalVolume_volume": "1", - "id": "e7d36200-92a5-11e9-ac62-1b173f839d9e", - "path": "single", - "pipette": "c6f45030-92a5-11e9-ac62-1b173f839d9e", - "preWetTip": false, - "stepDetails": "yeah notes", - "stepName": "transfer things", - "stepType": "moveLiquid", - "volume": "6", - }, - }, - }, - "name": "opentrons/protocol-designer", - "version": "3.0.0", - }, - "labware": Object { - "c6f4ec70-92a5-11e9-ac62-1b173f839d9e:tiprack-10ul": Object { - "definitionId": "fixture/fixture_regular_example_1/1", - "displayName": "tiprack 10ul (1)", - "slot": "1", - }, - "c6f51380-92a5-11e9-ac62-1b173f839d9e:tiprack-200ul": Object { - "definitionId": "fixture/fixture_regular_example_1/1", - "displayName": "tiprack 200ul (1)", - "slot": "2", - }, - "dafd4000-92a5-11e9-ac62-1b173f839d9e:96-deep-well": Object { - "definitionId": "fixture/fixture_regular_example_1/1", - "displayName": "96 deep well (1)", - "slot": "10", - }, - "trashId": Object { - "definitionId": "fixture/fixture_regular_example_1/1", - "displayName": "Trash", - "slot": "12", - }, - }, - "labwareDefinitions": Object { - "fixture/fixture_regular_example_1/1": Object { - "brand": Object { - "brand": "opentrons", - "brandId": Array [ - "t40u9sernisofsea", - ], - }, - "cornerOffsetFromSlot": Object { - "x": 0, - "y": 0, - "z": 0, - }, - "dimensions": Object { - "xDimension": 127.76, - "yDimension": 85.48, - "zDimension": 50, - }, - "groups": Array [ - Object { - "metadata": Object {}, - "wells": Array [ - "A1", - "A2", - ], - }, - ], - "metadata": Object { - "displayCategory": "wellPlate", - "displayName": "fake labware", - "displayVolumeUnits": "µL", - }, - "namespace": "fixture", - "ordering": Array [ - Array [ - "A1", - ], - Array [ - "A2", - ], - ], - "parameters": Object { - "format": "96Standard", - "isMagneticModuleCompatible": false, - "isTiprack": false, - "loadName": "fixture_regular_example_1", - }, - "schemaVersion": 2, - "version": 1, - "wells": Object { - "A1": Object { - "depth": 40, - "diameter": 30, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 10, - "y": 75.48, - "z": 15, - }, - "A2": Object { - "depth": 40, - "diameter": 30, - "shape": "circular", - "totalLiquidVolume": 100, - "x": 20, - "y": 75.48, - "z": 15, - }, - }, - }, - }, - "metadata": Object { - "author": "Author name", - "category": null, - "created": 1560957631666, - "description": "Description here", - "lastModified": undefined, - "protocolName": "Some name!", - "subcategory": null, - "tags": Array [], - }, - "pipettes": Object { - "c6f45030-92a5-11e9-ac62-1b173f839d9e": Object { - "mount": "left", - "name": "p10_single", - }, - "c6f47740-92a5-11e9-ac62-1b173f839d9e": Object { - "mount": "right", - "name": "p50_single", - }, - }, - "robot": Object { - "model": "OT-2 Standard", - }, - "schemaVersion": 3, -} -`; diff --git a/protocol-designer/src/load-file/migration/utils/getDefaultBlowoutFlowRate.ts b/protocol-designer/src/load-file/migration/utils/getDefaultBlowoutFlowRate.ts new file mode 100644 index 00000000000..7fa927177b4 --- /dev/null +++ b/protocol-designer/src/load-file/migration/utils/getDefaultBlowoutFlowRate.ts @@ -0,0 +1,36 @@ +import { LOW_VOLUME_PIPETTES, getPipetteSpecsV2 } from '@opentrons/shared-data' +import type { PipetteName } from '@opentrons/shared-data' + +export function getDefaultBlowoutFlowRate( + pipetteName: PipetteName, + volume: number, + tipLength: number +): number { + const specs = getPipetteSpecsV2(pipetteName) + + console.assert( + specs, + `expected to find pipette specs from pipetteName ${pipetteName} but could not` + ) + + const isLowVolumePipette = LOW_VOLUME_PIPETTES.includes(pipetteName) + const isUsingLowVolume = volume < 5 + const liquidType = + isLowVolumePipette && isUsingLowVolume ? 'lowVolumeDefault' : 'default' + const liquidSupportedTips = + specs != null ? Object.values(specs.liquids[liquidType].supportedTips) : [] + + // find the supported tip liquid specs that either exactly match + // tipLength or are closest, this accounts for custom tipracks + const matchingTipLiquidSpecs = liquidSupportedTips.sort((tipA, tipB) => { + const differenceA = Math.abs(tipA.defaultTipLength - tipLength) + const differenceB = Math.abs(tipB.defaultTipLength - tipLength) + return differenceA - differenceB + })[0] + console.assert( + matchingTipLiquidSpecs, + `expected to find the tip liquid specs but could not with pipetteName ${pipetteName}` + ) + + return matchingTipLiquidSpecs.defaultBlowOutFlowRate.default +} diff --git a/protocol-designer/src/localization/en/alert.json b/protocol-designer/src/localization/en/alert.json index 4548d19e57c..34ac8c33a02 100644 --- a/protocol-designer/src/localization/en/alert.json +++ b/protocol-designer/src/localization/en/alert.json @@ -53,10 +53,10 @@ "title": "Missing labware", "body": "One or more module has no labware on it. We recommend you add labware before proceeding" }, - "export_v8_protocol_7_1": { + "export_v8_1_protocol_7_3": { "title": "Robot and app update may be required", "body1": "This protocol can only run on app and robot server version", - "body2": "7.1 or higher", + "body2": "7.3.0 or higher", "body3": ". Please ensure your robot is updated to the correct version." }, "change_magnet_module_model": { @@ -218,6 +218,11 @@ "export": "Export", "import": "Import", "module_placement": { + "SLOTS_OCCUPIED": { + "title": "Cannot place module", + "single": "Slot {{slotName}} is occupied", + "multi": "Multiple slots are occupied" + }, "SLOT_OCCUPIED": { "title": "Cannot place module", "body": "Slot {{selectedSlot}} is occupied. Navigate to the design tab and remove the labware or remove the additional item to continue." diff --git a/protocol-designer/src/localization/en/feature_flags.json b/protocol-designer/src/localization/en/feature_flags.json index ebab1c9635d..7f2f9883bbd 100644 --- a/protocol-designer/src/localization/en/feature_flags.json +++ b/protocol-designer/src/localization/en/feature_flags.json @@ -11,13 +11,5 @@ "OT_PD_ALLOW_ALL_TIPRACKS": { "title": "Allow all tip rack options", "description": "Enable selection of all tip racks for each pipette." - }, - "OT_PD_ENABLE_MULTI_TIP": { - "title": "Enable multi tiprack support", - "description": "Allow users to select multiple tipracks per pipette" - }, - "OT_PD_ENABLE_MOAM": { - "title": "Enable multiples of a module", - "description": "Allow users to select multiples of a module" } } diff --git a/protocol-designer/src/localization/en/form.json b/protocol-designer/src/localization/en/form.json index 76876b2f5f0..ce2fda12bc5 100644 --- a/protocol-designer/src/localization/en/form.json +++ b/protocol-designer/src/localization/en/form.json @@ -83,7 +83,13 @@ "label": "delay" }, "tip_position": { "label": "tip position" }, - "flow_rate": { "label": "Flow Rate" }, + "flow_rate": { + "default_text": "The default {{displayName}} flow rate is optimal for handling aqueous liquids", + "error_decimals": "A max of {{decimals}} decimal places is allowed", + "error_out_of_bounds": "accepted range is {{min}} to {{max}}", + "label": "Flow Rate", + "range": "between {{min}} and {{max}}" + }, "volume": { "label": "volume per well" }, "well_order": { "label": "Well order", diff --git a/protocol-designer/src/localization/en/modal.json b/protocol-designer/src/localization/en/modal.json index a07cb3b1310..f02b0053466 100644 --- a/protocol-designer/src/localization/en/modal.json +++ b/protocol-designer/src/localization/en/modal.json @@ -42,6 +42,14 @@ "deckConfigAnd96Channel": { "body1": "Introducing the {{pd}} 8.0 with deck configuration and 96-channel pipette support!", "body2": "All protocols now require {{app}} version 7.1+ to run." + }, + "customParamsAndMultiTipAndModule": { + "body1": "Introducing {{pd}} 8.1. Starting today, you will be able to:", + "body2": "Customize blowout speed and height.", + "body3": "Adjust horizontal position within a well when aspirating, dispensing, or mixing.", + "body4": "Assign up to three types of tip racks to a single pipette.", + "body5": "Add multiple Temperature Modules to the deck (Flex only).", + "body6": "All protocols require {{app}} version 7.3.0 or later to run." } }, "labware_selection": { @@ -62,7 +70,7 @@ "tip_position": { "title": "Tip Positioning", "caption": "between {{min}} and {{max}}", - "warning": "The X and/or Y position value is close to edge of the well and might collide with it", + "warning": "One or more position offset values are close to the edge of the well and might collide with it", "radio_button": { "default": "{{defaultMmFromBottom}} mm from the bottom center (default)", "blowout": "0 mm from the top center (default)", @@ -169,7 +177,7 @@ "closeUnsavedStepForm": { "title": "Unsaved step form", "body": "You have not saved this step form. If you navigate away without saving, this step will be deleted.", - "confirm_button": "delete step" + "confirm_button": "discard step" }, "closeBatchEditForm": { "title": "Unsaved changes to multiple steps", @@ -264,6 +272,11 @@ "body2": "We have added new features since the last time this protocol was updated, but have not made any changes to existing protocol behavior. Because of this we do not expect any changes in how the robot will execute this protocol. To be safe we will still recommend keeping a separate copy of the file you just imported.", "body3": "As always, please contact us with any questions or feedback." }, + "toV8_1Migration": { + "body1": "Your protocol will be automatically updated to the latest version.", + "body2": "The default dispense height is now 1mm from the bottom of the well. If your protocol contains any dispense commands without a custom height, it will be automatically updated.", + "body3": "As always, please contact us with any questions or feedback." + }, "toV8Migration": { "body1": "Your protocol will be automatically updated to the latest version.", "body2": "{{pd}} no longer supports aspirate or mix actions in a trash bin. If your protocol contains these actions, an error icon will appear next to them in the Protocol Timeline. To resolve the error, choose another location for aspirating or mixing.", diff --git a/protocol-designer/src/localization/en/modules.json b/protocol-designer/src/localization/en/modules.json index 10a50dc0775..0f7911f45c4 100644 --- a/protocol-designer/src/localization/en/modules.json +++ b/protocol-designer/src/localization/en/modules.json @@ -1,4 +1,6 @@ { + "adapter_compatible_labware": "Adapter Compatible Labware", + "custom_labware": "Custom Labware", "additional_equipment_display_names": { "gripper": "Flex Gripper", "stagingAreas": "Staging Area Slots", @@ -6,6 +8,7 @@ "wasteChute": "Waste Chute" }, "module_display_names": { + "multipleTemperatureModuleTypes": "Multiple Temperatures", "temperatureModuleType": "Temperature", "magneticModuleType": "Magnetic", "thermocyclerModuleType": "Thermocycler", diff --git a/protocol-designer/src/localization/en/shared.json b/protocol-designer/src/localization/en/shared.json index 89d916bce35..41798ebbc15 100644 --- a/protocol-designer/src/localization/en/shared.json +++ b/protocol-designer/src/localization/en/shared.json @@ -1,7 +1,9 @@ { "add": "add", "amount": "Amount:", + "cancel": "Cancel", "confirm_reorder": "Are you sure you want to reorder these steps, it may cause errors?", + "done": "Done", "edit": "edit", "exit": "exit", "go_back": "go back", diff --git a/protocol-designer/src/localization/en/tooltip.json b/protocol-designer/src/localization/en/tooltip.json index 7ef580d81ce..b3ac4786fdc 100644 --- a/protocol-designer/src/localization/en/tooltip.json +++ b/protocol-designer/src/localization/en/tooltip.json @@ -8,6 +8,7 @@ "disabled_you_can_add_one_type": "Only one module of each type is allowed on the deck at a time", "not_enough_space_for_temp": "There is not enough space on the deck to add more temperature modules", "not_in_beta": "ⓘ Coming Soon", + "missing_tiprack": "Missing a tiprack? Make sure it is added to the deck", "step_description": { "heaterShaker": "Set heat, shake, or labware latch commands for the Heater-Shaker module", @@ -48,7 +49,8 @@ "mix_touchTip_mmFromBottom": "Distance from the bottom of the well", "preWetTip": "Pre-wet pipette tip by aspirating and dispensing 2/3 of the tip's max volume", "volume": "Volume to dispense in each well", - "blowout_z_offset": "The height at which blowout occurs from the top of the well" + "blowout_z_offset": "The height at which blowout occurs from the top of the well", + "blowout_flowRate": "Blowout speed" }, "indeterminate": { "aspirate_airGap_checkbox": "Not all selected steps are using this setting", diff --git a/protocol-designer/src/modules/__tests__/moduleData.test.tsx b/protocol-designer/src/modules/__tests__/moduleData.test.tsx new file mode 100644 index 00000000000..9d27732bf56 --- /dev/null +++ b/protocol-designer/src/modules/__tests__/moduleData.test.tsx @@ -0,0 +1,88 @@ +import { describe, it, expect } from 'vitest' +import { getNextAvailableModuleSlot } from '../moduleData' +import type { InitialDeckSetup } from '../../step-forms' + +describe('getNextAvailableModuleSlot', () => { + it('renders slot D1 when no slots are occupied', () => { + const mockInitialDeckSetup: InitialDeckSetup = { + modules: {}, + labware: {}, + pipettes: {}, + additionalEquipmentOnDeck: {}, + } + const result = getNextAvailableModuleSlot(mockInitialDeckSetup) + expect(result).toBe('D1') + }) + it('renders slot C1 when other slots are occupied', () => { + const mockInitialDeckSetup: InitialDeckSetup = { + modules: {}, + labware: {}, + pipettes: {}, + additionalEquipmentOnDeck: { + wasteChuteId: { + name: 'wasteChute', + id: 'wasteChuteId', + location: 'D3', + }, + trashBinId: { + name: 'trashBin', + id: 'trashBinId', + location: 'D1', + }, + }, + } + const result = getNextAvailableModuleSlot(mockInitialDeckSetup) + expect(result).toBe('C1') + }) + it('renders undefined when all slots are occupied', () => { + const mockInitialDeckSetup: InitialDeckSetup = { + modules: { + thermocycler: { + model: 'thermocyclerModuleV2', + id: 'thermocycler', + type: 'thermocyclerModuleType', + slot: 'B1', + moduleState: {} as any, + }, + temperature: { + model: 'temperatureModuleV2', + id: 'temperature', + type: 'temperatureModuleType', + slot: 'C1', + moduleState: {} as any, + }, + }, + labware: {}, + pipettes: {}, + additionalEquipmentOnDeck: { + wasteChuteId: { + name: 'wasteChute', + id: 'wasteChuteId', + location: 'D3', + }, + trashBinId: { + name: 'trashBin', + id: 'trashBinId', + location: 'D1', + }, + stagingArea1: { + name: 'stagingArea', + id: 'stagingArea1', + location: 'A3', + }, + stagingArea2: { + name: 'stagingArea', + id: 'stagingArea2', + location: 'B3', + }, + stagingArea3: { + name: 'stagingArea', + id: 'stagingArea3', + location: 'C3', + }, + }, + } + const result = getNextAvailableModuleSlot(mockInitialDeckSetup) + expect(result).toBe(undefined) + }) +}) diff --git a/protocol-designer/src/modules/index.ts b/protocol-designer/src/modules/index.ts index 82b41275ed4..8ca029f4e14 100644 --- a/protocol-designer/src/modules/index.ts +++ b/protocol-designer/src/modules/index.ts @@ -1 +1,2 @@ export * from './moduleData' +export * from './thunks' diff --git a/protocol-designer/src/modules/moduleData.ts b/protocol-designer/src/modules/moduleData.ts index a2d05f33bc8..240a2e11eae 100644 --- a/protocol-designer/src/modules/moduleData.ts +++ b/protocol-designer/src/modules/moduleData.ts @@ -1,14 +1,27 @@ -import { SPAN7_8_10_11_SLOT } from '../constants' +import { COLUMN_4_SLOTS } from '@opentrons/step-generation' import { MAGNETIC_MODULE_TYPE, TEMPERATURE_MODULE_TYPE, THERMOCYCLER_MODULE_TYPE, HEATERSHAKER_MODULE_TYPE, - ModuleType, MAGNETIC_BLOCK_TYPE, + MOVABLE_TRASH_ADDRESSABLE_AREAS, + WASTE_CHUTE_ADDRESSABLE_AREAS, + FIXED_TRASH_ID, +} from '@opentrons/shared-data' +import { SPAN7_8_10_11_SLOT } from '../constants' +import { getStagingAreaAddressableAreas } from '../utils' +import { getSlotIsEmpty } from '../step-forms' +import type { + ModuleType, RobotType, + CutoutId, + AddressableAreaName, } from '@opentrons/shared-data' -import { DropdownOption } from '@opentrons/components' +import type { DropdownOption } from '@opentrons/components' +import type { InitialDeckSetup } from '../step-forms' +import type { DeckSlot } from '../types' + export const SUPPORTED_MODULE_TYPES: ModuleType[] = [ HEATERSHAKER_MODULE_TYPE, MAGNETIC_BLOCK_TYPE, @@ -270,3 +283,32 @@ export function getAllModuleSlotsByType( } return slot } + +const FLEX_MODULE_SLOTS = ['D1', 'D3', 'C1', 'C3', 'B1', 'B3', 'A1', 'A3'] + +export function getNextAvailableModuleSlot( + initialDeckSetup: InitialDeckSetup +): DeckSlot | undefined { + return FLEX_MODULE_SLOTS.find(slot => { + const cutoutIds = Object.values(initialDeckSetup.additionalEquipmentOnDeck) + .filter(ae => ae.name === 'stagingArea') + .map(ae => ae.location as CutoutId) + const stagingAreaAddressableAreaNames = getStagingAreaAddressableAreas( + cutoutIds + ) + const addressableAreaName = stagingAreaAddressableAreaNames.find( + aa => aa === slot + ) + let isSlotEmpty: boolean = getSlotIsEmpty(initialDeckSetup, slot, true) + if (addressableAreaName == null && COLUMN_4_SLOTS.includes(slot)) { + isSlotEmpty = false + } else if ( + MOVABLE_TRASH_ADDRESSABLE_AREAS.includes(slot as AddressableAreaName) || + WASTE_CHUTE_ADDRESSABLE_AREAS.includes(slot as AddressableAreaName) || + slot === FIXED_TRASH_ID + ) { + isSlotEmpty = false + } + return isSlotEmpty + }) +} diff --git a/protocol-designer/src/modules/thunks.ts b/protocol-designer/src/modules/thunks.ts new file mode 100644 index 00000000000..655eeb07a7c --- /dev/null +++ b/protocol-designer/src/modules/thunks.ts @@ -0,0 +1,33 @@ +import { selectors as stepFormSelectors } from '../step-forms' +import { uuid } from '../utils' +import { getNextAvailableModuleSlot } from './moduleData' +import type { ModuleModel, ModuleType } from '@opentrons/shared-data' +import type { CreateModuleAction } from '../step-forms/actions' +import type { ThunkAction } from '../types' + +interface CreateModuleWithNoSloArgs { + type: ModuleType + model: ModuleModel +} +export const createModuleWithNoSlot: ( + args: CreateModuleWithNoSloArgs +) => ThunkAction = args => (dispatch, getState) => { + const { model, type } = args + const state = getState() + const initialDeckSetup = stepFormSelectors.getInitialDeckSetup(state) + const slot = getNextAvailableModuleSlot(initialDeckSetup) + + if (slot == null) { + console.assert(slot, 'expected to find available slot but could not') + } + + dispatch({ + type: 'CREATE_MODULE', + payload: { + model, + type, + slot: slot ?? '', + id: `${uuid()}:${type}}`, + }, + }) +} diff --git a/protocol-designer/src/step-forms/reducers/index.ts b/protocol-designer/src/step-forms/reducers/index.ts index a19cd27eeac..c901e2e8876 100644 --- a/protocol-designer/src/step-forms/reducers/index.ts +++ b/protocol-designer/src/step-forms/reducers/index.ts @@ -67,8 +67,10 @@ import { createPresavedStepForm, getDeckItemIdInSlot, getIdsInRange, + getUnoccupiedSlotForMoveableTrash, } from '../utils' -import { + +import type { CreateModuleAction, CreatePipettesAction, DeleteModuleAction, @@ -1379,6 +1381,14 @@ export const additionalEquipmentInvariantProperties = handleActions { const stagingAreaId = `${uuid()}:stagingArea` const cutoutId = getCutoutIdByAddressableArea( @@ -1452,7 +1462,6 @@ export const additionalEquipmentInvariantProperties = handleActions getLabwareDisplayName(def) ), @@ -455,7 +454,10 @@ export const getModulesForEditModulesCard: Selector< reduce( initialDeckSetup.modules, (acc, moduleOnDeck: ModuleOnDeck, id) => { - acc[moduleOnDeck.type] = moduleOnDeck + if (!acc[moduleOnDeck.type]) { + acc[moduleOnDeck.type] = [] + } + acc[moduleOnDeck.type]?.push(moduleOnDeck) return acc }, { diff --git a/protocol-designer/src/step-forms/test/createPresavedStepForm.test.ts b/protocol-designer/src/step-forms/test/createPresavedStepForm.test.ts index 11b93d8dbc6..326cb5ab742 100644 --- a/protocol-designer/src/step-forms/test/createPresavedStepForm.test.ts +++ b/protocol-designer/src/step-forms/test/createPresavedStepForm.test.ts @@ -141,7 +141,7 @@ describe('createPresavedStepForm', () => { pipette: 'leftPipetteId', nozzles: null, stepType: 'moveLiquid', - tipRack: null, + tipRack: 'defaultTipRack', // default fields dropTip_location: 'mockTrash', aspirate_airGap_checkbox: false, @@ -192,6 +192,7 @@ describe('createPresavedStepForm', () => { dispense_x_position: 0, dispense_y_position: 0, blowout_z_offset: 0, + blowout_flowRate: null, }) }) describe('mix step', () => { @@ -227,7 +228,8 @@ describe('createPresavedStepForm', () => { volume: undefined, aspirate_flowRate: null, dispense_flowRate: null, - tipRack: null, + tipRack: 'defaultTipRack', + blowout_flowRate: null, }) }) }) diff --git a/protocol-designer/src/step-forms/test/utils.test.ts b/protocol-designer/src/step-forms/test/utils.test.ts index f848fe1241d..d7dbe1960b5 100644 --- a/protocol-designer/src/step-forms/test/utils.test.ts +++ b/protocol-designer/src/step-forms/test/utils.test.ts @@ -1,5 +1,7 @@ import { describe, it, expect } from 'vitest' -import { getIdsInRange } from '../utils' +import { getIdsInRange, getUnoccupiedSlotForMoveableTrash } from '../utils' +import type { AddressableAreaName, CreateCommand } from '@opentrons/shared-data' + describe('getIdsInRange', () => { it('gets id in array of length 1', () => { expect(getIdsInRange(['X'], 'X', 'X')).toEqual(['X']) @@ -29,3 +31,126 @@ describe('getIdsInRange', () => { expect(getIdsInRange(orderedIds, 'T', 'T')).toEqual(['T']) }) }) +describe('getUnoccupiedSlotForMoveableTrash', () => { + it('returns slot C1 when all other slots are occupied by modules, labware, moveLabware, and staging areas', () => { + const mockPDFile: any = { + commands: [ + { + key: '7353ae60-c85e-45c4-8d69-59ff3a97debd', + commandType: 'loadModule', + params: { + model: 'thermocyclerModuleV2', + location: { slotName: 'B1' }, + moduleId: + '771f390f-01a9-4615-9c4e-4dbfc95844b5:thermocyclerModuleType', + }, + }, + { + key: '82e5d08f-ceae-4eb8-8600-b61a973d47d9', + commandType: 'loadModule', + params: { + model: 'heaterShakerModuleV1', + location: { slotName: 'D1' }, + moduleId: + 'b9df03af-3844-4ae8-a1cf-cae61a6b4992:heaterShakerModuleType', + }, + }, + { + key: '49bc2a29-a7d2-42a6-8610-e07a9ad166df', + commandType: 'loadModule', + params: { + model: 'temperatureModuleV2', + location: { slotName: 'D3' }, + moduleId: + '52bea856-eea6-473c-80df-b316f3559692:temperatureModuleType', + }, + }, + { + key: '864fadd7-f2c1-400a-b2ef-24d0c887a3c8', + commandType: 'loadLabware', + params: { + displayName: 'Opentrons Flex 96 Tip Rack 50 µL', + labwareId: + '88881828-037c-4445-ba57-121164f4a53a:opentrons/opentrons_flex_96_tiprack_50ul/1', + loadName: 'opentrons_flex_96_tiprack_50ul', + namespace: 'opentrons', + version: 1, + location: { slotName: 'C2' }, + }, + }, + { + key: '79994418-d664-4884-9441-4b0fa62bd143', + commandType: 'loadLabware', + params: { + displayName: 'Bio-Rad 96 Well Plate 200 µL PCR', + labwareId: + '733c04a8-ae8c-449f-a1f9-ca3783fdda58:opentrons/biorad_96_wellplate_200ul_pcr/2', + loadName: 'biorad_96_wellplate_200ul_pcr', + namespace: 'opentrons', + version: 2, + location: { addressableAreaName: 'A4' }, + }, + }, + { + key: 'b2170a2c-d202-4129-9cd7-ffa4e35d57bb', + commandType: 'loadLabware', + params: { + displayName: 'Corning 24 Well Plate 3.4 mL Flat', + labwareId: + '32e97c67-866e-4153-bcb7-2b86b1d3f1fe:opentrons/corning_24_wellplate_3.4ml_flat/2', + loadName: 'corning_24_wellplate_3.4ml_flat', + namespace: 'opentrons', + version: 2, + location: { slotName: 'B3' }, + }, + }, + { + key: 'fb1807fe-ca16-4f75-b44d-803d704c7d98', + commandType: 'loadLabware', + params: { + displayName: 'Opentrons Flex 96 Tip Rack 50 µL', + labwareId: + '11fdsa8b1-bf4b-4a6c-80cb-b8e5bdfe309b:opentrons/opentrons_flex_96_tiprack_50ul/1', + loadName: 'opentrons_flex_96_tiprack_50ul', + namespace: 'opentrons', + version: 1, + location: { + labwareId: + '32e97c67-866e-4153-bcb7-2b86b1d3f1fe:opentrons/corning_24_wellplate_3.4ml_flat/2', + }, + }, + }, + { + commandType: 'moveLabware', + key: '1395243a-958f-4305-9687-52cdaf39f2b6', + params: { + labwareId: + '733c04a8-ae8c-449f-a1f9-ca3783fdda58:opentrons/biorad_96_wellplate_200ul_pcr/2', + strategy: 'usingGripper', + newLocation: { slotName: 'C1' }, + }, + }, + { + commandType: 'moveLabware', + key: '4e39e7ec-4ada-4e3c-8369-1ff7421061a9', + params: { + labwareId: + '32e97c67-866e-4153-bcb7-2b86b1d3f1fe:opentrons/corning_24_wellplate_3.4ml_flat/2', + strategy: 'usingGripper', + newLocation: { addressableAreaName: 'A4' }, + }, + }, + ] as CreateCommand[], + } + const mockStagingAreaSlotNames: AddressableAreaName[] = ['A4', 'B4'] + const mockHasWasteChuteCommands = false + + expect( + getUnoccupiedSlotForMoveableTrash( + mockPDFile, + mockHasWasteChuteCommands, + mockStagingAreaSlotNames + ) + ).toStrictEqual('C3') + }) +}) diff --git a/protocol-designer/src/step-forms/types.ts b/protocol-designer/src/step-forms/types.ts index 81422cc985b..24dee9b0c46 100644 --- a/protocol-designer/src/step-forms/types.ts +++ b/protocol-designer/src/step-forms/types.ts @@ -72,7 +72,7 @@ export interface ModuleTemporalProperties { } export type ModuleOnDeck = ModuleEntity & ModuleTemporalProperties export type ModulesForEditModulesCard = Partial< - Record + Record > // =========== LABWARE ======== export type NormalizedLabwareById = Record< diff --git a/protocol-designer/src/step-forms/utils/createPresavedStepForm.ts b/protocol-designer/src/step-forms/utils/createPresavedStepForm.ts index 1ebfca8bf0c..5e3563683b0 100644 --- a/protocol-designer/src/step-forms/utils/createPresavedStepForm.ts +++ b/protocol-designer/src/step-forms/utils/createPresavedStepForm.ts @@ -132,11 +132,6 @@ const _patchDefaultTiprack = (args: { savedStepForms, orderedStepIds, } = args - const labware = initialDeckSetup.labware - const tipRackIds = Object.values(labware) - .filter(lw => lw.def.parameters.isTiprack) - .map(lw => lw.id) - const defaultPipetteId = getNextDefaultPipetteId( savedStepForms, orderedStepIds, @@ -145,15 +140,12 @@ const _patchDefaultTiprack = (args: { const pipetteFirstTiprackDefUri = pipetteEntities[defaultPipetteId].tiprackDefURI[0] - const defaultTiprackId = tipRackIds.find(id => - id.includes(pipetteFirstTiprackDefUri) - ) const formHasTipRackField = formData && 'tipRack' in formData - if (formHasTipRackField && defaultTiprackId != null) { + if (formHasTipRackField) { const updatedFields = handleFormChange( { - tipRack: defaultTiprackId, + tipRack: pipetteFirstTiprackDefUri, }, formData, pipetteEntities, diff --git a/protocol-designer/src/step-forms/utils/index.ts b/protocol-designer/src/step-forms/utils/index.ts index 73596b481c6..d9b2d108132 100644 --- a/protocol-designer/src/step-forms/utils/index.ts +++ b/protocol-designer/src/step-forms/utils/index.ts @@ -6,20 +6,23 @@ import { getPipetteSpecsV2, GEN_ONE_MULTI_PIPETTES, THERMOCYCLER_MODULE_TYPE, + THERMOCYCLER_MODULE_V2, + WASTE_CHUTE_CUTOUT, + FLEX_ROBOT_TYPE, } from '@opentrons/shared-data' import { SPAN7_8_10_11_SLOT, TC_SPAN_SLOTS } from '../../constants' import { hydrateField } from '../../steplist/fieldLevel' import { LabwareDefByDefURI } from '../../labware-defs' -import type { DeckSlotId, ModuleType } from '@opentrons/shared-data' +import { getCutoutIdByAddressableArea } from '../../utils' import type { - AdditionalEquipmentOnDeck, - InitialDeckSetup, - ModuleOnDeck, - FormPipettesByMount, - FormPipette, - LabwareOnDeck as LabwareOnDeckType, -} from '../types' -import type { DeckSlot } from '../../types' + AddressableAreaName, + CutoutId, + DeckSlotId, + LoadLabwareCreateCommand, + LoadModuleCreateCommand, + ModuleType, + MoveLabwareCreateCommand, +} from '@opentrons/shared-data' import type { NormalizedPipette, NormalizedPipetteById, @@ -28,9 +31,54 @@ import type { InvariantContext, ModuleEntity, } from '@opentrons/step-generation' +import type { DeckSlot } from '../../types' import type { FormData } from '../../form-types' +import type { PDProtocolFile } from '../../file-types' +import type { + AdditionalEquipmentOnDeck, + InitialDeckSetup, + ModuleOnDeck, + FormPipettesByMount, + FormPipette, + LabwareOnDeck as LabwareOnDeckType, +} from '../types' export { createPresavedStepForm } from './createPresavedStepForm' +const MOVABLE_TRASH_CUTOUTS = [ + { + value: 'cutoutA3', + slot: 'A3', + }, + { + value: 'cutoutA1', + slot: 'A1', + }, + { + value: 'cutoutB1', + slot: 'B1', + }, + { + value: 'cutoutB3', + slot: 'B3', + }, + { + value: 'cutoutC1', + slot: 'C1', + }, + { + value: 'cutoutC3', + slot: 'C3', + }, + { + value: 'cutoutD1', + slot: 'D1', + }, + { + value: 'cutoutD3', + slot: 'D3', + }, +] + const slotToCutoutOt2Map: { [key: string]: string } = { '1': 'cutout1', '2': 'cutout2', @@ -248,3 +296,82 @@ export function getHydratedForm( // @ts-expect-error(sa, 2021-6-14):type this properly in #3161 return hydratedForm } + +export const getUnoccupiedSlotForMoveableTrash = ( + file: PDProtocolFile, + hasWasteChuteCommands: boolean, + stagingAreaSlotNames: AddressableAreaName[] +): string => { + const wasteChuteSlot = hasWasteChuteCommands ? [WASTE_CHUTE_CUTOUT] : [] + const stagingAreaCutoutIds = stagingAreaSlotNames.map(slotName => + getCutoutIdByAddressableArea( + slotName, + 'stagingAreaRightSlot', + FLEX_ROBOT_TYPE + ) + ) + const allLoadLabwareSlotNames = Object.values(file.commands) + .filter( + (command): command is LoadLabwareCreateCommand => + command.commandType === 'loadLabware' + ) + .reduce((acc: string[], command) => { + const location = command.params.location + if ( + location !== 'offDeck' && + location !== null && + 'slotName' in location + ) { + return [...acc, location.slotName] + } + return acc + }, []) + + const allLoadModuleSlotNames = Object.values(file.commands) + .filter( + (command): command is LoadModuleCreateCommand => + command.commandType === 'loadModule' + ) + .flatMap(command => { + // special-casing Thermocycler + if (command.params.model === THERMOCYCLER_MODULE_V2) { + return ['A1', command.params.location.slotName] + } else { + return command.params.location.slotName + } + }) + + const allMoveLabwareLocations = Object.values(file.commands) + .filter( + (command): command is MoveLabwareCreateCommand => + command.commandType === 'moveLabware' + ) + .reduce((acc: string[], command) => { + const newLocation = command.params.newLocation + if ( + newLocation !== 'offDeck' && + newLocation !== null && + 'slotName' in newLocation + ) { + return [...acc, newLocation.slotName] + } + return acc + }, []) + + const unoccupiedSlot = MOVABLE_TRASH_CUTOUTS.find( + cutout => + !allLoadLabwareSlotNames.includes(cutout.slot) && + !allLoadModuleSlotNames.includes(cutout.slot) && + !allMoveLabwareLocations.includes(cutout.slot) && + !wasteChuteSlot.includes(cutout.value as typeof WASTE_CHUTE_CUTOUT) && + !stagingAreaCutoutIds.includes(cutout.value as CutoutId) + ) + if (unoccupiedSlot == null) { + console.error( + 'Expected to find an unoccupied slot for auto-generating a trash bin but could not' + ) + return '' + } + + return unoccupiedSlot.slot +} diff --git a/protocol-designer/src/steplist/formLevel/getDefaultsForStepType.ts b/protocol-designer/src/steplist/formLevel/getDefaultsForStepType.ts index b90eb6f028e..a6933bc85e4 100644 --- a/protocol-designer/src/steplist/formLevel/getDefaultsForStepType.ts +++ b/protocol-designer/src/steplist/formLevel/getDefaultsForStepType.ts @@ -41,6 +41,7 @@ export function getDefaultsForStepType( mix_x_position: 0, mix_y_position: 0, blowout_z_offset: DEFAULT_MM_BLOWOUT_OFFSET_FROM_TOP, + blowout_flowRate: null, } case 'moveLiquid': @@ -95,6 +96,7 @@ export function getDefaultsForStepType( aspirate_x_position: 0, aspirate_y_position: 0, blowout_z_offset: DEFAULT_MM_BLOWOUT_OFFSET_FROM_TOP, + blowout_flowRate: null, } case 'moveLabware': diff --git a/protocol-designer/src/steplist/formLevel/index.ts b/protocol-designer/src/steplist/formLevel/index.ts index 64c4fbff39b..6f003bdc77e 100644 --- a/protocol-designer/src/steplist/formLevel/index.ts +++ b/protocol-designer/src/steplist/formLevel/index.ts @@ -29,9 +29,8 @@ import { minDisposalVolume, minAspirateAirGapVolume, minDispenseAirGapVolume, - aspirateTipPositionInTube, - dispenseTipPositionInTube, mixTipPositionInTube, + tipPositionInTube, } from './warnings' import { HydratedFormdata, StepType } from '../../form-types' @@ -75,8 +74,7 @@ const stepFormHelperMap: Partial> = { minDisposalVolume, minAspirateAirGapVolume, minDispenseAirGapVolume, - aspirateTipPositionInTube, - dispenseTipPositionInTube + tipPositionInTube ), }, magnet: { diff --git a/protocol-designer/src/steplist/formLevel/moveLabwareFormErrors.ts b/protocol-designer/src/steplist/formLevel/moveLabwareFormErrors.ts index 28828c7524d..b9ee871772d 100644 --- a/protocol-designer/src/steplist/formLevel/moveLabwareFormErrors.ts +++ b/protocol-designer/src/steplist/formLevel/moveLabwareFormErrors.ts @@ -1,8 +1,9 @@ -import { LabwareLocation } from '@opentrons/shared-data' +import { getLabwareDefIsStandard } from '@opentrons/shared-data' import { COMPATIBLE_LABWARE_ALLOWLIST_BY_MODULE_TYPE, COMPATIBLE_LABWARE_ALLOWLIST_FOR_ADAPTER, } from '../../utils/labwareModuleCompatibility' +import type { LabwareLocation } from '@opentrons/shared-data' import type { InvariantContext, LabwareEntity, @@ -11,15 +12,18 @@ import type { ProfileFormError } from './profileErrors' type HydratedFormData = any -// TODO(Jr, 1/16/24): look into the use case of this util since the i18n strings -// previously listed in this util were not found in any json. const getMoveLabwareError = ( labware: LabwareEntity, newLocation: LabwareLocation, invariantContext: InvariantContext ): string | null => { let errorString: string | null = null - if (labware == null || newLocation == null || newLocation === 'offDeck') + if ( + labware == null || + newLocation == null || + newLocation === 'offDeck' || + !getLabwareDefIsStandard(labware?.def) + ) return null const selectedLabwareDefUri = labware?.labwareDefURI if ('moduleId' in newLocation) { diff --git a/protocol-designer/src/steplist/formLevel/stepFormToArgs/mixFormToArgs.ts b/protocol-designer/src/steplist/formLevel/stepFormToArgs/mixFormToArgs.ts index d28f6dc42df..4b22040578f 100644 --- a/protocol-designer/src/steplist/formLevel/stepFormToArgs/mixFormToArgs.ts +++ b/protocol-designer/src/steplist/formLevel/stepFormToArgs/mixFormToArgs.ts @@ -70,7 +70,7 @@ export const mixFormToArgs = ( : null // Blowout settings const blowoutFlowRateUlSec = - hydratedFormData.dispense_flowRate ?? + hydratedFormData.blowout_flowRate ?? matchingTipLiquidSpecs?.defaultBlowOutFlowRate.default const blowoutOffsetFromTopMm = blowoutLocation diff --git a/protocol-designer/src/steplist/formLevel/stepFormToArgs/moveLiquidFormToArgs.ts b/protocol-designer/src/steplist/formLevel/stepFormToArgs/moveLiquidFormToArgs.ts index 05910f13332..04f87317ff0 100644 --- a/protocol-designer/src/steplist/formLevel/stepFormToArgs/moveLiquidFormToArgs.ts +++ b/protocol-designer/src/steplist/formLevel/stepFormToArgs/moveLiquidFormToArgs.ts @@ -202,7 +202,7 @@ export const moveLiquidFormToArgs = ( dispenseOffsetFromBottomMm: fields.dispense_mmFromBottom || DEFAULT_MM_FROM_BOTTOM_DISPENSE, blowoutFlowRateUlSec: - fields.dispense_flowRate || + fields.blowout_flowRate || matchingTipLiquidSpecs.defaultBlowOutFlowRate.default, blowoutOffsetFromTopMm, changeTip: fields.changeTip, diff --git a/protocol-designer/src/steplist/formLevel/test/getDefaultsForStepType.test.ts b/protocol-designer/src/steplist/formLevel/test/getDefaultsForStepType.test.ts index 081d7809566..2d2d1fa5e25 100644 --- a/protocol-designer/src/steplist/formLevel/test/getDefaultsForStepType.test.ts +++ b/protocol-designer/src/steplist/formLevel/test/getDefaultsForStepType.test.ts @@ -52,6 +52,7 @@ describe('getDefaultsForStepType', () => { blowout_checkbox: false, blowout_location: null, + blowout_flowRate: null, preWetTip: false, aspirate_airGap_checkbox: false, @@ -87,6 +88,7 @@ describe('getDefaultsForStepType', () => { mix_wellOrder_second: DEFAULT_WELL_ORDER_SECOND_OPTION, blowout_checkbox: false, blowout_location: null, + blowout_flowRate: null, mix_mmFromBottom: DEFAULT_MM_FROM_BOTTOM_DISPENSE, mix_touchTip_mmFromBottom: null, mix_touchTip_checkbox: false, diff --git a/protocol-designer/src/steplist/formLevel/test/warnings.test.ts b/protocol-designer/src/steplist/formLevel/test/warnings.test.ts index 16b1c5030f3..04c8cfe93db 100644 --- a/protocol-designer/src/steplist/formLevel/test/warnings.test.ts +++ b/protocol-designer/src/steplist/formLevel/test/warnings.test.ts @@ -5,8 +5,7 @@ import { belowPipetteMinimumVolume, minDisposalVolume, maxDispenseWellVolume, - aspirateTipPositionInTube, - dispenseTipPositionInTube, + tipPositionInTube, mixTipPositionInTube, } from '../warnings' import type { LabwareEntity } from '@opentrons/step-generation' @@ -294,26 +293,20 @@ describe('Max dispense well volume', () => { dispense_mmFromBottom: null, } }) - it('renders the errors for all 3', () => { - expect(aspirateTipPositionInTube(fields)?.type).toBe( - 'ASPIRATE_TIP_POSITIONED_LOW_IN_TUBE' - ) - expect(dispenseTipPositionInTube(fields)?.type).toBe( - 'DISPENSE_TIP_POSITIONED_LOW_IN_TUBE' - ) + it('renders the errors for all 2', () => { + expect(tipPositionInTube(fields)?.type).toBe('TIP_POSITIONED_LOW_IN_TUBE') expect(mixTipPositionInTube(fields)?.type).toBe( 'MIX_TIP_POSITIONED_LOW_IN_TUBE' ) }) - it('renders null for all 3 when the number has been adjusted', () => { + it('renders null for both when the number has been adjusted', () => { fields.aspirate_mmFromBottom = 3 fields.dispense_mmFromBottom = 3 fields.mix_mmFromBottom = 3 - expect(aspirateTipPositionInTube(fields)).toBe(null) - expect(dispenseTipPositionInTube(fields)).toBe(null) + expect(tipPositionInTube(fields)).toBe(null) expect(mixTipPositionInTube(fields)).toBe(null) }) - it('renders null for all 3 when the labware is not a tube rack', () => { + it('renders null for both when the labware is not a tube rack', () => { fields.aspirate_labware = { def: fixture96Plate as LabwareDefinition2, id: 'mockId', @@ -329,8 +322,7 @@ describe('Max dispense well volume', () => { id: 'mockId', labwareDefURI: 'mockURI', } - expect(aspirateTipPositionInTube(fields)).toBe(null) - expect(dispenseTipPositionInTube(fields)).toBe(null) + expect(tipPositionInTube(fields)).toBe(null) expect(mixTipPositionInTube(fields)).toBe(null) }) }) diff --git a/protocol-designer/src/steplist/formLevel/warnings.tsx b/protocol-designer/src/steplist/formLevel/warnings.tsx index 6a9c31a1a72..f19527d72f1 100644 --- a/protocol-designer/src/steplist/formLevel/warnings.tsx +++ b/protocol-designer/src/steplist/formLevel/warnings.tsx @@ -2,18 +2,18 @@ import * as React from 'react' import { getWellTotalVolume } from '@opentrons/shared-data' import { KnowledgeBaseLink } from '../../components/KnowledgeBaseLink' import type { FormError } from './errors' + /******************* ** Warning Messages ** ********************/ export type FormWarningType = - | 'ASPIRATE_TIP_POSITIONED_LOW_IN_TUBE' | 'BELOW_MIN_AIR_GAP_VOLUME' | 'BELOW_MIN_DISPOSAL_VOLUME' | 'BELOW_PIPETTE_MINIMUM_VOLUME' - | 'DISPENSE_TIP_POSITIONED_LOW_IN_TUBE' | 'OVER_MAX_WELL_VOLUME' | 'MIX_TIP_POSITIONED_LOW_IN_TUBE' + | 'TIP_POSITIONED_LOW_IN_TUBE' export type FormWarning = FormError & { type: FormWarningType @@ -59,18 +59,11 @@ const belowMinDisposalVolumeWarning = (min: number): FormWarning => ({ dependentFields: ['disposalVolume_volume', 'pipette'], }) -const aspirateTipPositionedLowInTube = (): FormWarning => ({ - type: 'ASPIRATE_TIP_POSITIONED_LOW_IN_TUBE', +const tipPositionedLowInTube = (): FormWarning => ({ + type: 'TIP_POSITIONED_LOW_IN_TUBE', title: - 'The default aspirate height is 1mm from the bottom of the well, which could cause liquid overflow or pipette damage. Edit tip position in advanced settings.', - dependentFields: ['aspirate_labware'], -}) - -const dispenseTipPositionedLowInTube = (): FormWarning => ({ - type: 'DISPENSE_TIP_POSITIONED_LOW_IN_TUBE', - title: - 'The default dispense height is 0.5mm from the bottom of the well, which could cause liquid overflow or pipette damage. Edit tip position in advanced settings.', - dependentFields: ['dispense_labware'], + 'A tuberack has an aspirate and dispense default height at 1mm and 0.5mm from the bottom of the well, which could cause liquid overflow or pipette damage. Edit tip position in advanced settings.', + dependentFields: ['aspirate_labware', 'dispense_labware'], }) const mixTipPositionedLowInTube = (): FormWarning => ({ @@ -88,34 +81,39 @@ export type WarningChecker = (val: unknown) => FormWarning | null // TODO: real HydratedFormData type export type HydratedFormData = any -export const aspirateTipPositionInTube = ( +export const tipPositionInTube = ( fields: HydratedFormData ): FormWarning | null => { - const { aspirate_labware, aspirate_mmFromBottom } = fields - let isTubeRack: boolean = false + const { + aspirate_labware, + aspirate_mmFromBottom, + dispense_labware, + dispense_mmFromBottom, + } = fields + let isAspirateTubeRack: boolean = false + let isDispenseTubeRack: boolean = false if (aspirate_labware != null) { - isTubeRack = aspirate_labware.def.metadata.displayCategory === 'tubeRack' + isAspirateTubeRack = + aspirate_labware.def.metadata.displayCategory === 'tubeRack' } - return isTubeRack && aspirate_mmFromBottom === null - ? aspirateTipPositionedLowInTube() - : null -} -export const dispenseTipPositionInTube = ( - fields: HydratedFormData -): FormWarning | null => { - const { dispense_labware, dispense_mmFromBottom } = fields - let isTubeRack: boolean = false if (dispense_labware != null) { - isTubeRack = + isDispenseTubeRack = // checking that the dispense labware is a labware and not a trash/waste chute 'def' in dispense_labware ? dispense_labware.def.metadata.displayCategory === 'tubeRack' : false } - return isTubeRack && dispense_mmFromBottom === null - ? dispenseTipPositionedLowInTube() - : null + + if ( + (isAspirateTubeRack && aspirate_mmFromBottom === null) || + (isDispenseTubeRack && dispense_mmFromBottom === null) + ) { + return tipPositionedLowInTube() + } else { + return null + } } + export const mixTipPositionInTube = ( fields: HydratedFormData ): FormWarning | null => { diff --git a/protocol-designer/src/steplist/generateSubstepItem.ts b/protocol-designer/src/steplist/generateSubstepItem.ts index edfac2fd19e..2c58befeeda 100644 --- a/protocol-designer/src/steplist/generateSubstepItem.ts +++ b/protocol-designer/src/steplist/generateSubstepItem.ts @@ -112,8 +112,12 @@ export const mergeSubstepRowsSingleChannel = (args: { showDispenseVol: boolean }): StepItemSourceDestRow[] => { const { substepRows, showDispenseVol } = args + // TODO(jr, 5/2/24): filtering out air gap steps for now since a refactor would be required + // to figure out if the air gap is for the aspirate or dispense labware. Otherwise, a white screen + // was happening with an air gap step trying to happen in an aspirate labware well that did not exist + const filteredSubstepRows = substepRows.filter(row => !row.isAirGap) return steplistUtils.mergeWhen( - substepRows, + filteredSubstepRows, ( currentRow, nextRow // NOTE: if aspirate then dispense rows are adjacent, collapse them into one row @@ -160,8 +164,12 @@ export const mergeSubstepRowsMultiChannel = (args: { showDispenseVol: boolean }): StepItemSourceDestRow[][] => { const { substepRows, channels, isMixStep, showDispenseVol } = args + // TODO(jr, 5/2/24): filtering out air gap steps for now since a refactor would be required + // to figure out if the air gap is for the aspirate or dispense labware. Otherwise, a white screen + // was happening with an air gap step trying to happen in an aspirate labware well that did not exist + const filteredSubstepRows = substepRows.filter(row => !row.isAirGap) return steplistUtils.mergeWhen( - substepRows, + filteredSubstepRows, ( currentMultiRow: SubstepTimelineFrame, nextMultiRow: SubstepTimelineFrame diff --git a/protocol-designer/src/steplist/substepTimeline.ts b/protocol-designer/src/steplist/substepTimeline.ts index 19971df04fc..d164a33bedf 100644 --- a/protocol-designer/src/steplist/substepTimeline.ts +++ b/protocol-designer/src/steplist/substepTimeline.ts @@ -64,11 +64,23 @@ const _createNextTimelineFrame = (args: { volume: args.volume, activeTips: _getNewActiveTips(args.nextFrame.commands.slice(0, args.index)), } + const command = args.command + const isAirGapCommand = + 'meta' in command && command.meta != null && 'isAirGap' in command.meta + const newTimelineFrame = args.command.commandType === 'aspirate' || args.command.commandType === 'aspirateInPlace' - ? { ..._newTimelineFrameKeys, source: args.wellInfo } - : { ..._newTimelineFrameKeys, dest: args.wellInfo } + ? { + ..._newTimelineFrameKeys, + source: args.wellInfo, + isAirGap: isAirGapCommand, + } + : { + ..._newTimelineFrameKeys, + dest: args.wellInfo, + isAirGap: isAirGapCommand, + } return newTimelineFrame } diff --git a/protocol-designer/src/steplist/test/__snapshots__/mergeSubstepsFns.test.ts.snap b/protocol-designer/src/steplist/test/__snapshots__/mergeSubstepsFns.test.ts.snap index 77a3cc5bbb1..87122a8b5d0 100644 --- a/protocol-designer/src/steplist/test/__snapshots__/mergeSubstepsFns.test.ts.snap +++ b/protocol-designer/src/steplist/test/__snapshots__/mergeSubstepsFns.test.ts.snap @@ -1011,1015 +1011,3 @@ exports[`mergeSubstepRowsMultiChannel > mock transfer 1`] = ` ], ] `; - -exports[`mergeSubstepRowsMultiChannel mock consolidate 1`] = ` -Array [ - Array [ - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": undefined, - "source": Object { - "postIngreds": Object { - "ingred1Id": 25, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "A1", - }, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": undefined, - "source": Object { - "postIngreds": undefined, - "preIngreds": undefined, - "well": undefined, - }, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": undefined, - "source": Object { - "postIngreds": undefined, - "preIngreds": undefined, - "well": undefined, - }, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": undefined, - "source": Object { - "postIngreds": undefined, - "preIngreds": undefined, - "well": undefined, - }, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": undefined, - "source": Object { - "postIngreds": undefined, - "preIngreds": undefined, - "well": undefined, - }, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": undefined, - "source": Object { - "postIngreds": undefined, - "preIngreds": undefined, - "well": undefined, - }, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": undefined, - "source": Object { - "postIngreds": undefined, - "preIngreds": undefined, - "well": undefined, - }, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": undefined, - "source": Object { - "postIngreds": undefined, - "preIngreds": undefined, - "well": undefined, - }, - "volume": 5, - }, - ], - Array [ - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 10, - }, - "preIngreds": Object {}, - "well": "A12", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 31, - }, - "preIngreds": Object { - "ingred1Id": 36, - }, - "well": "A2", - }, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 10, - }, - "preIngreds": Object {}, - "well": "B12", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 31, - }, - "preIngreds": Object { - "ingred1Id": 36, - }, - "well": "B2", - }, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 10, - }, - "preIngreds": Object {}, - "well": "C12", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 31, - }, - "preIngreds": Object { - "ingred1Id": 36, - }, - "well": "C2", - }, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 10, - }, - "preIngreds": Object {}, - "well": "D12", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 31, - }, - "preIngreds": Object { - "ingred1Id": 36, - }, - "well": "D2", - }, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 10, - }, - "preIngreds": Object {}, - "well": "E12", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 31, - }, - "preIngreds": Object { - "ingred1Id": 36, - }, - "well": "E2", - }, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 10, - }, - "preIngreds": Object {}, - "well": "F12", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 31, - }, - "preIngreds": Object { - "ingred1Id": 36, - }, - "well": "F2", - }, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 10, - }, - "preIngreds": Object {}, - "well": "G12", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 31, - }, - "preIngreds": Object { - "ingred1Id": 36, - }, - "well": "G2", - }, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 10, - }, - "preIngreds": Object {}, - "well": "H12", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 31, - }, - "preIngreds": Object { - "ingred1Id": 36, - }, - "well": "H2", - }, - "volume": 5, - }, - ], -] -`; - -exports[`mergeSubstepRowsMultiChannel mock distribute 1`] = ` -Array [ - Array [ - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 5, - }, - "preIngreds": Object {}, - "well": "A11", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "A1", - }, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 5, - }, - "preIngreds": Object {}, - "well": "B11", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "B1", - }, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 5, - }, - "preIngreds": Object {}, - "well": "C11", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "C1", - }, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 5, - }, - "preIngreds": Object {}, - "well": "D11", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "D1", - }, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 5, - }, - "preIngreds": Object {}, - "well": "E11", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "E1", - }, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 5, - }, - "preIngreds": Object {}, - "well": "F11", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "F1", - }, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 5, - }, - "preIngreds": Object {}, - "well": "G11", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "G1", - }, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 5, - }, - "preIngreds": Object {}, - "well": "H11", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "H1", - }, - "volume": 5, - }, - ], - Array [ - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 5, - }, - "preIngreds": Object {}, - "well": "A12", - }, - "source": undefined, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 5, - }, - "preIngreds": Object {}, - "well": "B12", - }, - "source": undefined, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 5, - }, - "preIngreds": Object {}, - "well": "C12", - }, - "source": undefined, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 5, - }, - "preIngreds": Object {}, - "well": "D12", - }, - "source": undefined, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 5, - }, - "preIngreds": Object {}, - "well": "E12", - }, - "source": undefined, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 5, - }, - "preIngreds": Object {}, - "well": "F12", - }, - "source": undefined, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 5, - }, - "preIngreds": Object {}, - "well": "G12", - }, - "source": undefined, - "volume": 5, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 5, - }, - "preIngreds": Object {}, - "well": "H12", - }, - "source": undefined, - "volume": 5, - }, - ], -] -`; - -exports[`mergeSubstepRowsMultiChannel mock mix 1`] = ` -Array [ - Array [ - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "A1", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "A1", - }, - "volume": 10, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "B1", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "B1", - }, - "volume": 10, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "C1", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "C1", - }, - "volume": 10, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "D1", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "D1", - }, - "volume": 10, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "E1", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "E1", - }, - "volume": 10, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "F1", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "F1", - }, - "volume": 10, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "G1", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "G1", - }, - "volume": 10, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "H1", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "H1", - }, - "volume": 10, - }, - ], -] -`; - -exports[`mergeSubstepRowsMultiChannel mock transfer 1`] = ` -Array [ - Array [ - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 10, - }, - "preIngreds": Object {}, - "well": "A12", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "A1", - }, - "volume": 10, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 10, - }, - "preIngreds": Object {}, - "well": "B12", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "B1", - }, - "volume": 10, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 10, - }, - "preIngreds": Object {}, - "well": "C12", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "C1", - }, - "volume": 10, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 10, - }, - "preIngreds": Object {}, - "well": "D12", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "D1", - }, - "volume": 10, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 10, - }, - "preIngreds": Object {}, - "well": "E12", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "E1", - }, - "volume": 10, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 10, - }, - "preIngreds": Object {}, - "well": "F12", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "F1", - }, - "volume": 10, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 10, - }, - "preIngreds": Object {}, - "well": "G12", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "G1", - }, - "volume": 10, - }, - Object { - "activeTips": Object { - "labware": "someTiprackId", - "well": "A6", - }, - "dest": Object { - "postIngreds": Object { - "ingred1Id": 10, - }, - "preIngreds": Object {}, - "well": "H12", - }, - "source": Object { - "postIngreds": Object { - "ingred1Id": 20, - }, - "preIngreds": Object { - "ingred1Id": 30, - }, - "well": "H1", - }, - "volume": 10, - }, - ], -] -`; diff --git a/protocol-designer/src/steplist/test/generateSubsteps.test.ts b/protocol-designer/src/steplist/test/generateSubsteps.test.ts index 1c2483e0487..194e3303442 100644 --- a/protocol-designer/src/steplist/test/generateSubsteps.test.ts +++ b/protocol-designer/src/steplist/test/generateSubsteps.test.ts @@ -4,9 +4,11 @@ import { makeContext, FIXED_TRASH_ID, } from '@opentrons/step-generation' +import { fixtureTiprack300ul, getLabwareDefURI } from '@opentrons/shared-data' import { THERMOCYCLER_STATE } from '../../constants' import { generateSubstepItem } from '../generateSubstepItem' +import type { LabwareDefinition2 } from '@opentrons/shared-data' import type { RobotState, InvariantContext, @@ -181,7 +183,7 @@ describe('generateSubstepItem', () => { dispenseFlowRateUlSec: 5, dispenseOffsetFromBottomMm: 10, dropTipLocation: FIXED_TRASH_ID, - tipRack: 'tiprack1Id', + tipRack: getLabwareDefURI(fixtureTiprack300ul as LabwareDefinition2), } }) ;[ @@ -231,6 +233,7 @@ describe('generateSubstepItem', () => { preIngreds: {}, well: 'C1', }, + isAirGap: false, }, ], }, @@ -269,6 +272,7 @@ describe('generateSubstepItem', () => { preIngreds: {}, well: 'A1', }, + isAirGap: false, source: { postIngreds: {}, preIngreds: {}, @@ -323,6 +327,7 @@ describe('generateSubstepItem', () => { labwareId: tiprackId, wellName: 'A1', }, + isAirGap: false, source: { well: 'A1', preIngreds: {}, postIngreds: {} }, dest: { well: 'A1', @@ -343,6 +348,7 @@ describe('generateSubstepItem', () => { labwareId: tiprackId, wellName: 'A1', }, + isAirGap: false, dest: { postIngreds: { __air__: { @@ -400,7 +406,7 @@ describe('generateSubstepItem', () => { aspirateFlowRateUlSec: 5, dispenseFlowRateUlSec: 5, dropTipLocation: FIXED_TRASH_ID, - tipRack: 'tiprack1Id', + tipRack: getLabwareDefURI(fixtureTiprack300ul as LabwareDefinition2), }, // @ts-expect-error(sa, 2021-6-15): errors should be boolean typed errors: {}, @@ -434,6 +440,7 @@ describe('generateSubstepItem', () => { preIngreds: {}, well: 'A1', }, + isAirGap: false, source: { postIngreds: {}, preIngreds: {}, @@ -460,6 +467,7 @@ describe('generateSubstepItem', () => { }, well: 'A1', }, + isAirGap: false, source: { postIngreds: { __air__: { @@ -490,6 +498,7 @@ describe('generateSubstepItem', () => { preIngreds: {}, well: 'A2', }, + isAirGap: false, source: { postIngreds: {}, preIngreds: {}, @@ -516,6 +525,7 @@ describe('generateSubstepItem', () => { }, well: 'A2', }, + isAirGap: false, source: { postIngreds: { __air__: { diff --git a/protocol-designer/src/steplist/types.ts b/protocol-designer/src/steplist/types.ts index 297c13e7194..6855104c5dd 100644 --- a/protocol-designer/src/steplist/types.ts +++ b/protocol-designer/src/steplist/types.ts @@ -48,6 +48,7 @@ export interface SourceDestData { postIngreds: WellIngredientVolumeData } export interface SubstepTimelineFrame { + isAirGap?: boolean substepIndex?: number activeTips: TipLocation | null | undefined source?: SourceDestData diff --git a/protocol-designer/src/timelineMiddleware/__tests__/generateRobotStateTimeline.test.ts b/protocol-designer/src/timelineMiddleware/__tests__/generateRobotStateTimeline.test.ts index 1717dc838cb..795512828dc 100644 --- a/protocol-designer/src/timelineMiddleware/__tests__/generateRobotStateTimeline.test.ts +++ b/protocol-designer/src/timelineMiddleware/__tests__/generateRobotStateTimeline.test.ts @@ -10,6 +10,11 @@ import { } from '@opentrons/step-generation' import { generateRobotStateTimeline } from '../generateRobotStateTimeline' import type { StepArgsAndErrorsById } from '../../steplist' +import { + LabwareDefinition2, + fixtureTiprack300ul, + getLabwareDefURI, +} from '@opentrons/shared-data' vi.mock('../../labware-defs/utils') @@ -49,7 +54,7 @@ describe('generateRobotStateTimeline', () => { mixBeforeAspirate: null, description: null, nozzles: null, - tipRack: 'tiprack1Id', + tipRack: getLabwareDefURI(fixtureTiprack300ul as LabwareDefinition2), aspirateXOffset: 0, aspirateYOffset: 0, dispenseXOffset: 0, @@ -89,7 +94,7 @@ describe('generateRobotStateTimeline', () => { mixBeforeAspirate: null, description: null, nozzles: null, - tipRack: 'tiprack1Id', + tipRack: getLabwareDefURI(fixtureTiprack300ul as LabwareDefinition2), aspirateXOffset: 0, aspirateYOffset: 0, dispenseXOffset: 0, @@ -121,7 +126,7 @@ describe('generateRobotStateTimeline', () => { aspirateDelaySeconds: null, dispenseDelaySeconds: null, nozzles: null, - tipRack: 'tiprack1Id', + tipRack: getLabwareDefURI(fixtureTiprack300ul as LabwareDefinition2), aspirateXOffset: 0, aspirateYOffset: 0, dispenseXOffset: 0, diff --git a/protocol-designer/src/top-selectors/labware-locations/index.ts b/protocol-designer/src/top-selectors/labware-locations/index.ts index 9396bd121b8..6c66367fb4f 100644 --- a/protocol-designer/src/top-selectors/labware-locations/index.ts +++ b/protocol-designer/src/top-selectors/labware-locations/index.ts @@ -11,6 +11,7 @@ import { STAGING_AREA_RIGHT_SLOT_FIXTURE, isAddressableAreaStandardSlot, MOVABLE_TRASH_ADDRESSABLE_AREAS, + FLEX_MODULE_ADDRESSABLE_AREAS, } from '@opentrons/shared-data' import { COLUMN_4_SLOTS } from '@opentrons/step-generation' import { @@ -232,7 +233,8 @@ export const getUnoccupiedLabwareLocationOptions: Selector< .includes(slotId) && !isTrashSlot && !WASTE_CHUTE_ADDRESSABLE_AREAS.includes(slotId) && - !notSelectedStagingAreaAddressableAreas.includes(slotId) + !notSelectedStagingAreaAddressableAreas.includes(slotId) && + !FLEX_MODULE_ADDRESSABLE_AREAS.includes(slotId) ) }) .map(slotId => ({ name: slotId, value: slotId })) diff --git a/protocol-designer/src/top-selectors/substep-highlight.ts b/protocol-designer/src/top-selectors/substep-highlight.ts index 1e47785be88..1144b81fe59 100644 --- a/protocol-designer/src/top-selectors/substep-highlight.ts +++ b/protocol-designer/src/top-selectors/substep-highlight.ts @@ -202,13 +202,19 @@ function _getSelectedWellsForSubstep( // source + dest steps - // @ts-expect-error(sa, 2021-6-22): `sourceLabware` is missing in `MixArgs` - if (stepArgs.sourceLabware && stepArgs.sourceLabware === labwareId) { + if ( + 'sourceLabware' in stepArgs && + stepArgs.sourceLabware != null && + stepArgs.sourceLabware === labwareId + ) { wells.push(...getWells('source')) } - // @ts-expect-error(sa, 2021-6-22): property `destLabware` is missing in `MixArgs` - if (stepArgs.destLabware && stepArgs.destLabware === labwareId) { + if ( + 'destLabware' in stepArgs && + stepArgs.destLabware != null && + stepArgs.destLabware === labwareId + ) { wells.push(...getWells('dest')) } diff --git a/protocol-designer/src/tutorial/index.ts b/protocol-designer/src/tutorial/index.ts index 58a0f522c60..6d82f7832c9 100644 --- a/protocol-designer/src/tutorial/index.ts +++ b/protocol-designer/src/tutorial/index.ts @@ -11,7 +11,7 @@ type HintKey = // normal hints | 'waste_chute_warning' // blocking hints | 'custom_labware_with_modules' - | 'export_v8_protocol_7_1' + | 'export_v8_1_protocol_7_3' | 'change_magnet_module_model' // DEPRECATED HINTS (keep a record to avoid name collisions with old persisted dismissal states) // 'export_v4_protocol' @@ -20,5 +20,6 @@ type HintKey = // normal hints // | 'export_v6_protocol_6_10' // | 'export_v6_protocol_6_20' // | 'export_v7_protocol_7_0' +// | 'export_v8_protocol_7_1' export { actions, rootReducer, selectors } export type { RootState, HintKey } diff --git a/protocol-designer/src/ui/labware/selectors.ts b/protocol-designer/src/ui/labware/selectors.ts index dd4be8f0c62..669d265a427 100644 --- a/protocol-designer/src/ui/labware/selectors.ts +++ b/protocol-designer/src/ui/labware/selectors.ts @@ -241,22 +241,22 @@ export const getDisposalOptions = createSelector( } ) -export const getTiprackOptions: Selector = createSelector( +export const getTiprackOptions: Selector = createSelector( stepFormSelectors.getLabwareEntities, getLabwareNicknamesById, (labwareEntities, nicknamesById) => { const options = reduce( labwareEntities, ( - acc: Options, + acc: DropdownOption[], labwareEntity: LabwareEntity, labwareId: string - ): Options => { + ): DropdownOption[] => { const labwareDefURI = labwareEntity.labwareDefURI - const optionValues = acc.map(option => option.value) + const optionDefURI = acc.map(option => option.value) if ( - optionValues.includes(labwareDefURI) || + optionDefURI.includes(labwareDefURI) || !getIsTiprack(labwareEntity.def) ) { return acc @@ -265,13 +265,13 @@ export const getTiprackOptions: Selector = createSelector( ...acc, { name: nicknamesById[labwareId], - value: labwareId, + value: labwareDefURI, }, ] } }, [] ) - return _sortLabwareDropdownOptions(options) + return options } ) diff --git a/protocol-designer/src/ui/steps/test/selectors.test.ts b/protocol-designer/src/ui/steps/test/selectors.test.ts index e5aa13d10c5..22b93569b04 100644 --- a/protocol-designer/src/ui/steps/test/selectors.test.ts +++ b/protocol-designer/src/ui/steps/test/selectors.test.ts @@ -418,7 +418,10 @@ describe('_getSavedMultiSelectFieldValues', () => { isIndeterminate: false, value: undefined, }, - + blowout_flowRate: { + isIndeterminate: false, + value: undefined, + }, aspirate_labware: { value: 'aspirate_labware_id', isIndeterminate: false, @@ -642,6 +645,7 @@ describe('_getSavedMultiSelectFieldValues', () => { dispense_wellOrder_first: 'b2t', dispense_wellOrder_second: 'r2l', dispense_mix_checkbox: false, + blowout_flowRate: null, // same thing here with mix times or mix volumes dispense_delay_checkbox: false, // same thing here for delay seconds and mm from bottom @@ -670,6 +674,9 @@ describe('_getSavedMultiSelectFieldValues', () => { tipRack: { isIndeterminate: false, }, + blowout_flowRate: { + isIndeterminate: true, + }, aspirate_flowRate: { isIndeterminate: true, }, @@ -862,6 +869,9 @@ describe('_getSavedMultiSelectFieldValues', () => { ).toEqual({ volume: { value: '100', isIndeterminate: false }, tipRack: { isIndeterminate: false }, + blowout_flowRate: { + isIndeterminate: false, + }, times: { value: null, isIndeterminate: false }, changeTip: { value: 'always', isIndeterminate: false }, labware: { value: 'some_labware_id', isIndeterminate: false }, @@ -940,6 +950,9 @@ describe('_getSavedMultiSelectFieldValues', () => { ) ).toEqual({ tipRack: { isIndeterminate: false }, + blowout_flowRate: { + isIndeterminate: false, + }, volume: { isIndeterminate: true }, times: { isIndeterminate: true }, changeTip: { isIndeterminate: true }, diff --git a/protocol-designer/vite.config.ts b/protocol-designer/vite.config.ts index 70d055a6fd8..3c5acc81248 100644 --- a/protocol-designer/vite.config.ts +++ b/protocol-designer/vite.config.ts @@ -1,12 +1,13 @@ import path from 'path' -import { UserConfig, defineConfig } from 'vite' +import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import postCssImport from 'postcss-import' import postCssApply from 'postcss-apply' import postColorModFunction from 'postcss-color-mod-function' import postCssPresetEnv from 'postcss-preset-env' import lostCss from 'lost' -import { versionForProject } from '../scripts/git-version' +import { versionForProject } from '../scripts/git-version.mjs' +import type { UserConfig } from 'vite' const testAliases: {} | { 'file-saver': string } = process.env.CYPRESS === '1' @@ -69,6 +70,9 @@ export default defineConfig( ...testAliases, }, }, + server: { + port: 5178 + } } } ) diff --git a/react-api-client/src/protocols/__tests__/useCreateProtocolAnalysisMutation.test.tsx b/react-api-client/src/protocols/__tests__/useCreateProtocolAnalysisMutation.test.tsx new file mode 100644 index 00000000000..e04c020fb1d --- /dev/null +++ b/react-api-client/src/protocols/__tests__/useCreateProtocolAnalysisMutation.test.tsx @@ -0,0 +1,77 @@ +import * as React from 'react' +import { describe, it, expect, beforeEach, vi } from 'vitest' +import { QueryClient, QueryClientProvider } from 'react-query' +import { act, renderHook, waitFor } from '@testing-library/react' +import { createProtocolAnalysis } from '@opentrons/api-client' +import { useHost } from '../../api' +import { useCreateProtocolAnalysisMutation } from '..' +import type { HostConfig, Response } from '@opentrons/api-client' +import type { ProtocolAnalysisSummary } from '@opentrons/shared-data' + +vi.mock('@opentrons/api-client') +vi.mock('../../api/useHost') + +const HOST_CONFIG: HostConfig = { hostname: 'localhost' } +const ANALYSIS_SUMMARY_RESPONSE = [ + { id: 'fakeAnalysis1', status: 'completed' }, + { id: 'fakeAnalysis2', status: 'pending' }, +] as ProtocolAnalysisSummary[] + +describe('useCreateProtocolAnalysisMutation hook', () => { + let wrapper: React.FunctionComponent<{ children: React.ReactNode }> + + beforeEach(() => { + const queryClient = new QueryClient() + const clientProvider: React.FunctionComponent<{ + children: React.ReactNode + }> = ({ children }) => ( + {children} + ) + wrapper = clientProvider + }) + + it('should return no data when calling createProtocolAnalysis if the request fails', async () => { + vi.mocked(useHost).mockReturnValue(HOST_CONFIG) + vi.mocked(createProtocolAnalysis).mockRejectedValue('oh no') + + const { result } = renderHook( + () => useCreateProtocolAnalysisMutation('fake-protocol-key'), + { + wrapper, + } + ) + + expect(result.current.data).toBeUndefined() + result.current.createProtocolAnalysis({ + protocolKey: 'fake-protocol-key', + runTimeParameterValues: {}, + }) + await waitFor(() => { + expect(result.current.data).toBeUndefined() + }) + }) + + it('should create an array of ProtocolAnalysisSummaries when calling the createProtocolAnalysis callback', async () => { + vi.mocked(useHost).mockReturnValue(HOST_CONFIG) + vi.mocked(createProtocolAnalysis).mockResolvedValue({ + data: ANALYSIS_SUMMARY_RESPONSE, + } as Response) + + const { result } = renderHook( + () => useCreateProtocolAnalysisMutation('fake-protocol-key'), + { + wrapper, + } + ) + act(() => + result.current.createProtocolAnalysis({ + protocolKey: 'fake-protocol-key', + runTimeParameterValues: {}, + }) + ) + + await waitFor(() => { + expect(result.current.data).toEqual(ANALYSIS_SUMMARY_RESPONSE) + }) + }) +}) diff --git a/react-api-client/src/protocols/index.ts b/react-api-client/src/protocols/index.ts index ddf7c3eeaac..561dee01e8b 100644 --- a/react-api-client/src/protocols/index.ts +++ b/react-api-client/src/protocols/index.ts @@ -4,4 +4,5 @@ export { useProtocolQuery } from './useProtocolQuery' export { useProtocolAnalysesQuery } from './useProtocolAnalysesQuery' export { useProtocolAnalysisAsDocumentQuery } from './useProtocolAnalysisAsDocumentQuery' export { useCreateProtocolMutation } from './useCreateProtocolMutation' +export { useCreateProtocolAnalysisMutation } from './useCreateProtocolAnalysisMutation' export { useDeleteProtocolMutation } from './useDeleteProtocolMutation' diff --git a/react-api-client/src/protocols/useCreateProtocolAnalysisMutation.ts b/react-api-client/src/protocols/useCreateProtocolAnalysisMutation.ts new file mode 100644 index 00000000000..f8ba6e10586 --- /dev/null +++ b/react-api-client/src/protocols/useCreateProtocolAnalysisMutation.ts @@ -0,0 +1,86 @@ +import { createProtocolAnalysis } from '@opentrons/api-client' +import { useMutation, useQueryClient } from 'react-query' +import { useHost } from '../api' +import type { + ErrorResponse, + HostConfig, + RunTimeParameterCreateData, +} from '@opentrons/api-client' +import type { ProtocolAnalysisSummary } from '@opentrons/shared-data' +import type { AxiosError } from 'axios' +import type { + UseMutationResult, + UseMutationOptions, + UseMutateFunction, +} from 'react-query' + +export interface CreateProtocolAnalysisVariables { + protocolKey: string + runTimeParameterValues?: RunTimeParameterCreateData + forceReAnalyze?: boolean +} +export type UseCreateProtocolMutationResult = UseMutationResult< + ProtocolAnalysisSummary[], + AxiosError, + CreateProtocolAnalysisVariables +> & { + createProtocolAnalysis: UseMutateFunction< + ProtocolAnalysisSummary[], + AxiosError, + CreateProtocolAnalysisVariables + > +} + +export type UseCreateProtocolAnalysisMutationOptions = UseMutationOptions< + ProtocolAnalysisSummary[], + AxiosError, + CreateProtocolAnalysisVariables +> + +export function useCreateProtocolAnalysisMutation( + protocolId: string | null, + hostOverride?: HostConfig | null, + options: UseCreateProtocolAnalysisMutationOptions | undefined = {} +): UseCreateProtocolMutationResult { + const contextHost = useHost() + const host = + hostOverride != null ? { ...contextHost, ...hostOverride } : contextHost + const queryClient = useQueryClient() + + const mutation = useMutation< + ProtocolAnalysisSummary[], + AxiosError, + CreateProtocolAnalysisVariables + >( + [host, 'protocols', protocolId, 'analyses'], + ({ protocolKey, runTimeParameterValues, forceReAnalyze }) => + createProtocolAnalysis( + host as HostConfig, + protocolKey, + runTimeParameterValues, + forceReAnalyze + ) + .then(response => { + queryClient + .invalidateQueries([host, 'protocols', protocolId, 'analyses']) + .then(() => + queryClient.setQueryData( + [host, 'protocols', protocolId, 'analyses'], + response.data + ) + ) + .catch((e: Error) => { + throw e + }) + return response.data + }) + .catch((e: Error) => { + throw e + }), + options + ) + return { + ...mutation, + createProtocolAnalysis: mutation.mutate, + } +} diff --git a/react-api-client/src/robot/__tests__/useRobotSettingsQuery.test.tsx b/react-api-client/src/robot/__tests__/useRobotSettingsQuery.test.tsx new file mode 100644 index 00000000000..2f980be9473 --- /dev/null +++ b/react-api-client/src/robot/__tests__/useRobotSettingsQuery.test.tsx @@ -0,0 +1,81 @@ +import * as React from 'react' +import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest' +import { QueryClient, QueryClientProvider } from 'react-query' +import { renderHook, waitFor } from '@testing-library/react' + +import { getRobotSettings } from '@opentrons/api-client' +import { useHost } from '../../api' +import { useRobotSettingsQuery } from '..' + +import type { + HostConfig, + Response, + RobotSettingsResponse, +} from '@opentrons/api-client' +import type { UseRobotSettingsQueryOptions } from '../useRobotSettingsQuery' + +vi.mock('@opentrons/api-client') +vi.mock('../../api/useHost') + +const HOST_CONFIG: HostConfig = { hostname: 'localhost' } +const ROBOT_SETTINGS_RESPONSE: RobotSettingsResponse = { + settings: [ + { + id: 'enableOEMMode', + title: 'Enable OEM Mode', + description: 'a mode for an OEM', + value: false, + }, + ], +} + +describe('useRobotSettingsQuery hook', () => { + let wrapper: React.FunctionComponent< + { children: React.ReactNode } & UseRobotSettingsQueryOptions + > + + beforeEach(() => { + const queryClient = new QueryClient() + const clientProvider: React.FunctionComponent< + { children: React.ReactNode } & UseRobotSettingsQueryOptions + > = ({ children }) => ( + {children} + ) + + wrapper = clientProvider + }) + + afterEach(() => { + vi.resetAllMocks() + }) + + it('should return no data if no host', () => { + vi.mocked(useHost).mockReturnValue(null) + + const { result } = renderHook(() => useRobotSettingsQuery(), { wrapper }) + + expect(result.current?.data).toBeUndefined() + }) + + it('should return no data if robot settings request fails', () => { + vi.mocked(useHost).mockReturnValue(HOST_CONFIG) + vi.mocked(getRobotSettings).mockRejectedValue('oh no') + + const { result } = renderHook(() => useRobotSettingsQuery(), { wrapper }) + + expect(result.current?.data).toBeUndefined() + }) + + it('should return robot settings response data', async () => { + vi.mocked(useHost).mockReturnValue(HOST_CONFIG) + vi.mocked(getRobotSettings).mockResolvedValue({ + data: ROBOT_SETTINGS_RESPONSE, + } as Response) + + const { result } = renderHook(() => useRobotSettingsQuery(), { wrapper }) + + await waitFor(() => { + expect(result.current?.data).toEqual(ROBOT_SETTINGS_RESPONSE) + }) + }) +}) diff --git a/react-api-client/src/robot/index.ts b/react-api-client/src/robot/index.ts index 8a539abcea9..0ac1c3341b5 100644 --- a/react-api-client/src/robot/index.ts +++ b/react-api-client/src/robot/index.ts @@ -3,3 +3,5 @@ export { useEstopQuery } from './useEstopQuery' export { useLightsQuery } from './useLightsQuery' export { useAcknowledgeEstopDisengageMutation } from './useAcknowledgeEstopDisengageMutation' export { useSetLightsMutation } from './useSetLightsMutation' +export { useRobotSettingsQuery } from './useRobotSettingsQuery' +export { useUpdateRobotSettingMutation } from './useUpdateRobotSettingMutation' diff --git a/react-api-client/src/robot/useRobotSettingsQuery.ts b/react-api-client/src/robot/useRobotSettingsQuery.ts new file mode 100644 index 00000000000..455457ec83b --- /dev/null +++ b/react-api-client/src/robot/useRobotSettingsQuery.ts @@ -0,0 +1,21 @@ +import { useQuery } from 'react-query' +import { getRobotSettings } from '@opentrons/api-client' +import { useHost } from '../api' + +import type { UseQueryResult, UseQueryOptions } from 'react-query' +import type { HostConfig, RobotSettingsResponse } from '@opentrons/api-client' + +export type UseRobotSettingsQueryOptions = UseQueryOptions + +export function useRobotSettingsQuery( + options: UseRobotSettingsQueryOptions = {} +): UseQueryResult { + const host = useHost() + const query = useQuery( + [host as HostConfig, 'robot_settings'], + () => getRobotSettings(host as HostConfig).then(response => response.data), + { enabled: host !== null, ...options } + ) + + return query +} diff --git a/react-api-client/src/robot/useUpdateRobotSettingMutation.ts b/react-api-client/src/robot/useUpdateRobotSettingMutation.ts new file mode 100644 index 00000000000..83765fb5a70 --- /dev/null +++ b/react-api-client/src/robot/useUpdateRobotSettingMutation.ts @@ -0,0 +1,68 @@ +import { useMutation } from 'react-query' +import { updateRobotSetting } from '@opentrons/api-client' +import { useHost } from '../api' + +import type { AxiosError } from 'axios' +import type { + UseMutateFunction, + UseMutationOptions, + UseMutationResult, +} from 'react-query' +import type { + ErrorResponse, + HostConfig, + RobotSettings, +} from '@opentrons/api-client' + +export interface UpdateRobotSettingVariables { + id: string + value: boolean +} + +export type UseUpdateRobotSettingMutationResult = UseMutationResult< + RobotSettings, + AxiosError, + UpdateRobotSettingVariables +> & { + updateRobotSetting: UseMutateFunction< + RobotSettings, + AxiosError, + UpdateRobotSettingVariables + > +} + +export type UseUpdateRobotSettingnMutationOptions = UseMutationOptions< + RobotSettings, + AxiosError, + UpdateRobotSettingVariables +> + +export function useUpdateRobotSettingMutation( + options: UseUpdateRobotSettingnMutationOptions = {} +): UseUpdateRobotSettingMutationResult { + const host = useHost() + // const queryClient = useQueryClient() + + const mutation = useMutation< + RobotSettings, + AxiosError, + UpdateRobotSettingVariables + >( + [host, 'robot_settings'], + ({ id, value }) => + updateRobotSetting(host as HostConfig, id, value).then(response => { + // TODO: investigate ODD top level behavior when invalidating this query + // queryClient + // .invalidateQueries([host, 'robot_settings']) + // .catch((e: Error) => { + // throw e + // }) + return response.data?.settings ?? [] + }), + options + ) + return { + ...mutation, + updateRobotSetting: mutation.mutate, + } +} diff --git a/react-api-client/src/runs/__fixtures__/runs.ts b/react-api-client/src/runs/__fixtures__/runs.ts index e97ed37ca63..9320df9fbea 100644 --- a/react-api-client/src/runs/__fixtures__/runs.ts +++ b/react-api-client/src/runs/__fixtures__/runs.ts @@ -32,6 +32,7 @@ export const mockPausedRun: RunData = { pipettes: [], labware: [], modules: [], + runTimeParameters: [], } export const mockRunningRun: RunData = { @@ -61,6 +62,7 @@ export const mockRunningRun: RunData = { pipettes: [], labware: [], modules: [], + runTimeParameters: [], } export const mockRunResponse: Run = { diff --git a/react-api-client/src/runs/index.ts b/react-api-client/src/runs/index.ts index a77e01b2b42..5790abb860b 100644 --- a/react-api-client/src/runs/index.ts +++ b/react-api-client/src/runs/index.ts @@ -10,6 +10,7 @@ export { usePauseRunMutation } from './usePauseRunMutation' export { useStopRunMutation } from './useStopRunMutation' export { useRunActionMutations } from './useRunActionMutations' export { useAllCommandsQuery } from './useAllCommandsQuery' +export { useAllCommandsAsPreSerializedList } from './useAllCommandsAsPreSerializedList' export { useCommandQuery } from './useCommandQuery' export * from './useCreateLabwareOffsetMutation' export * from './useCreateLabwareDefinitionMutation' diff --git a/react-api-client/src/runs/useAllCommandsAsPreSerializedList.ts b/react-api-client/src/runs/useAllCommandsAsPreSerializedList.ts new file mode 100644 index 00000000000..3d30d13c579 --- /dev/null +++ b/react-api-client/src/runs/useAllCommandsAsPreSerializedList.ts @@ -0,0 +1,52 @@ +import { UseQueryResult, useQuery } from 'react-query' +import { getCommandsAsPreSerializedList } from '@opentrons/api-client' +import { useHost } from '../api' +import type { UseQueryOptions } from 'react-query' +import type { + GetCommandsParams, + HostConfig, + CommandsData, + RunCommandSummary, +} from '@opentrons/api-client' + +const DEFAULT_PAGE_LENGTH = 30 +export const DEFAULT_PARAMS: GetCommandsParams = { + cursor: null, + pageLength: DEFAULT_PAGE_LENGTH, +} + +export function useAllCommandsAsPreSerializedList( + runId: string | null, + params?: GetCommandsParams | null, + options: UseQueryOptions = {} +): UseQueryResult { + const host = useHost() + const nullCheckedParams = params ?? DEFAULT_PARAMS + + const allOptions: UseQueryOptions = { + ...options, + enabled: host !== null && runId != null && options.enabled !== false, + } + const { cursor, pageLength } = nullCheckedParams + const query = useQuery( + [host, 'runs', runId, 'getCommandsAsPreSerializedList', cursor, pageLength], + () => { + return getCommandsAsPreSerializedList( + host as HostConfig, + runId as string, + nullCheckedParams + ).then(response => { + const responseData = response.data + return { + ...responseData, + data: responseData.data.map( + command => JSON.parse(command) as RunCommandSummary + ), + } + }) + }, + allOptions + ) + + return query +} diff --git a/react-api-client/src/runs/useAllCommandsQuery.ts b/react-api-client/src/runs/useAllCommandsQuery.ts index bb542bd8370..f258b61836f 100644 --- a/react-api-client/src/runs/useAllCommandsQuery.ts +++ b/react-api-client/src/runs/useAllCommandsQuery.ts @@ -16,21 +16,25 @@ export const DEFAULT_PARAMS: GetCommandsParams = { export function useAllCommandsQuery( runId: string | null, - params: GetCommandsParams = DEFAULT_PARAMS, + params?: GetCommandsParams | null, options: UseQueryOptions = {} ): UseQueryResult { const host = useHost() + const nullCheckedParams = params ?? DEFAULT_PARAMS + const allOptions: UseQueryOptions = { ...options, enabled: host !== null && runId != null && options.enabled !== false, } - const { cursor, pageLength } = params + const { cursor, pageLength } = nullCheckedParams const query = useQuery( [host, 'runs', runId, 'commands', cursor, pageLength], () => { - return getCommands(host as HostConfig, runId as string, params).then( - response => response.data - ) + return getCommands( + host as HostConfig, + runId as string, + nullCheckedParams + ).then(response => response.data) }, allOptions ) diff --git a/react-api-client/src/system/index.ts b/react-api-client/src/system/index.ts index 10dc4d8ba66..faabb1e9f35 100644 --- a/react-api-client/src/system/index.ts +++ b/react-api-client/src/system/index.ts @@ -1,2 +1,3 @@ export { useAuthorization } from './useAuthorization' export { useConnectionsQuery } from './useConnectionsQuery' +export { useCreateSplashMutation } from './useCreateSplashMutation' diff --git a/react-api-client/src/system/useCreateSplashMutation.ts b/react-api-client/src/system/useCreateSplashMutation.ts new file mode 100644 index 00000000000..783dc1cf7b4 --- /dev/null +++ b/react-api-client/src/system/useCreateSplashMutation.ts @@ -0,0 +1,58 @@ +import { useMutation } from 'react-query' +import { createSplash } from '@opentrons/api-client' +import { useHost } from '../api' + +import type { AxiosError, AxiosResponse } from 'axios' +import type { + UseMutationResult, + UseMutationOptions, + UseMutateFunction, +} from 'react-query' +import type { ErrorResponse, HostConfig } from '@opentrons/api-client' + +export interface CreateSplashRequestData { + file: File +} +export type UseCreateSplashMutationResult = UseMutationResult< + AxiosResponse, + AxiosError, + CreateSplashRequestData +> & { + createSplash: UseMutateFunction< + AxiosResponse, + AxiosError, + CreateSplashRequestData + > +} + +export type UseCreateSplashMutationOptions = UseMutationOptions< + AxiosResponse, + AxiosError, + CreateSplashRequestData +> + +export function useCreateSplashMutation( + options: UseCreateSplashMutationOptions = {}, + hostOverride?: HostConfig | null +): UseCreateSplashMutationResult { + const contextHost = useHost() + const host = + hostOverride != null ? { ...contextHost, ...hostOverride } : contextHost + + const mutation = useMutation< + AxiosResponse, + AxiosError, + CreateSplashRequestData + >( + [host, 'splash'], + ({ file }) => + createSplash(host as HostConfig, file).catch(e => { + throw e + }), + options + ) + return { + ...mutation, + createSplash: mutation.mutate, + } +} diff --git a/robot-server/Pipfile b/robot-server/Pipfile index e6c1b7ba794..2d22c6dc34c 100755 --- a/robot-server/Pipfile +++ b/robot-server/Pipfile @@ -36,9 +36,11 @@ sqlalchemy2-stubs = "==0.0.2a21" # limited by tavern python-box = "==6.1.0" types-paho-mqtt = "==1.6.0.20240106" +performance-metrics = {file = "../performance-metrics", editable = true} [packages] anyio = "==3.7.1" +aiohttp = "==3.8.1" # fastapi >=0.100.0 is intended for use with pydantic 2.x, and while it theoretically is # backwards compatible, best to be sure fastapi = "==0.99.1" diff --git a/robot-server/Pipfile.lock b/robot-server/Pipfile.lock index e97832aab95..2ea9f545696 100644 --- a/robot-server/Pipfile.lock +++ b/robot-server/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "d56512f7ae8f68fd80ec6eff41af08576468087a45578f5b2c8241e42d95b887" + "sha256": "9f64ba7d87b9c9fd510aac5c4a22fa748c1bb3b9936826ef2b4b13454c1c5e2b" }, "pipfile-spec": 6, "requires": { @@ -16,6 +16,85 @@ ] }, "default": { + "aiohttp": { + "hashes": [ + "sha256:01d7bdb774a9acc838e6b8f1d114f45303841b89b95984cbb7d80ea41172a9e3", + "sha256:03a6d5349c9ee8f79ab3ff3694d6ce1cfc3ced1c9d36200cb8f08ba06bd3b782", + "sha256:04d48b8ce6ab3cf2097b1855e1505181bdd05586ca275f2505514a6e274e8e75", + "sha256:0770e2806a30e744b4e21c9d73b7bee18a1cfa3c47991ee2e5a65b887c49d5cf", + "sha256:07b05cd3305e8a73112103c834e91cd27ce5b4bd07850c4b4dbd1877d3f45be7", + "sha256:086f92daf51a032d062ec5f58af5ca6a44d082c35299c96376a41cbb33034675", + "sha256:099ebd2c37ac74cce10a3527d2b49af80243e2a4fa39e7bce41617fbc35fa3c1", + "sha256:0c7ebbbde809ff4e970824b2b6cb7e4222be6b95a296e46c03cf050878fc1785", + "sha256:102e487eeb82afac440581e5d7f8f44560b36cf0bdd11abc51a46c1cd88914d4", + "sha256:11691cf4dc5b94236ccc609b70fec991234e7ef8d4c02dd0c9668d1e486f5abf", + "sha256:11a67c0d562e07067c4e86bffc1553f2cf5b664d6111c894671b2b8712f3aba5", + "sha256:12de6add4038df8f72fac606dff775791a60f113a725c960f2bab01d8b8e6b15", + "sha256:13487abd2f761d4be7c8ff9080de2671e53fff69711d46de703c310c4c9317ca", + "sha256:15b09b06dae900777833fe7fc4b4aa426556ce95847a3e8d7548e2d19e34edb8", + "sha256:1c182cb873bc91b411e184dab7a2b664d4fea2743df0e4d57402f7f3fa644bac", + "sha256:1ed0b6477896559f17b9eaeb6d38e07f7f9ffe40b9f0f9627ae8b9926ae260a8", + "sha256:28d490af82bc6b7ce53ff31337a18a10498303fe66f701ab65ef27e143c3b0ef", + "sha256:2e5d962cf7e1d426aa0e528a7e198658cdc8aa4fe87f781d039ad75dcd52c516", + "sha256:2ed076098b171573161eb146afcb9129b5ff63308960aeca4b676d9d3c35e700", + "sha256:2f2f69dca064926e79997f45b2f34e202b320fd3782f17a91941f7eb85502ee2", + "sha256:31560d268ff62143e92423ef183680b9829b1b482c011713ae941997921eebc8", + "sha256:31d1e1c0dbf19ebccbfd62eff461518dcb1e307b195e93bba60c965a4dcf1ba0", + "sha256:37951ad2f4a6df6506750a23f7cbabad24c73c65f23f72e95897bb2cecbae676", + "sha256:3af642b43ce56c24d063325dd2cf20ee012d2b9ba4c3c008755a301aaea720ad", + "sha256:44db35a9e15d6fe5c40d74952e803b1d96e964f683b5a78c3cc64eb177878155", + "sha256:473d93d4450880fe278696549f2e7aed8cd23708c3c1997981464475f32137db", + "sha256:477c3ea0ba410b2b56b7efb072c36fa91b1e6fc331761798fa3f28bb224830dd", + "sha256:4a4a4e30bf1edcad13fb0804300557aedd07a92cabc74382fdd0ba6ca2661091", + "sha256:4aed991a28ea3ce320dc8ce655875e1e00a11bdd29fe9444dd4f88c30d558602", + "sha256:51467000f3647d519272392f484126aa716f747859794ac9924a7aafa86cd411", + "sha256:55c3d1072704d27401c92339144d199d9de7b52627f724a949fc7d5fc56d8b93", + "sha256:589c72667a5febd36f1315aa6e5f56dd4aa4862df295cb51c769d16142ddd7cd", + "sha256:5bfde62d1d2641a1f5173b8c8c2d96ceb4854f54a44c23102e2ccc7e02f003ec", + "sha256:5c23b1ad869653bc818e972b7a3a79852d0e494e9ab7e1a701a3decc49c20d51", + "sha256:61bfc23df345d8c9716d03717c2ed5e27374e0fe6f659ea64edcd27b4b044cf7", + "sha256:6ae828d3a003f03ae31915c31fa684b9890ea44c9c989056fea96e3d12a9fa17", + "sha256:6c7cefb4b0640703eb1069835c02486669312bf2f12b48a748e0a7756d0de33d", + "sha256:6d69f36d445c45cda7b3b26afef2fc34ef5ac0cdc75584a87ef307ee3c8c6d00", + "sha256:6f0d5f33feb5f69ddd57a4a4bd3d56c719a141080b445cbf18f238973c5c9923", + "sha256:6f8b01295e26c68b3a1b90efb7a89029110d3a4139270b24fda961893216c440", + "sha256:713ac174a629d39b7c6a3aa757b337599798da4c1157114a314e4e391cd28e32", + "sha256:718626a174e7e467f0558954f94af117b7d4695d48eb980146016afa4b580b2e", + "sha256:7187a76598bdb895af0adbd2fb7474d7f6025d170bc0a1130242da817ce9e7d1", + "sha256:71927042ed6365a09a98a6377501af5c9f0a4d38083652bcd2281a06a5976724", + "sha256:7d08744e9bae2ca9c382581f7dce1273fe3c9bae94ff572c3626e8da5b193c6a", + "sha256:7dadf3c307b31e0e61689cbf9e06be7a867c563d5a63ce9dca578f956609abf8", + "sha256:81e3d8c34c623ca4e36c46524a3530e99c0bc95ed068fd6e9b55cb721d408fb2", + "sha256:844a9b460871ee0a0b0b68a64890dae9c415e513db0f4a7e3cab41a0f2fedf33", + "sha256:8b7ef7cbd4fec9a1e811a5de813311ed4f7ac7d93e0fda233c9b3e1428f7dd7b", + "sha256:97ef77eb6b044134c0b3a96e16abcb05ecce892965a2124c566af0fd60f717e2", + "sha256:99b5eeae8e019e7aad8af8bb314fb908dd2e028b3cdaad87ec05095394cce632", + "sha256:a25fa703a527158aaf10dafd956f7d42ac6d30ec80e9a70846253dd13e2f067b", + "sha256:a2f635ce61a89c5732537a7896b6319a8fcfa23ba09bec36e1b1ac0ab31270d2", + "sha256:a79004bb58748f31ae1cbe9fa891054baaa46fb106c2dc7af9f8e3304dc30316", + "sha256:a996d01ca39b8dfe77440f3cd600825d05841088fd6bc0144cc6c2ec14cc5f74", + "sha256:b0e20cddbd676ab8a64c774fefa0ad787cc506afd844de95da56060348021e96", + "sha256:b6613280ccedf24354406caf785db748bebbddcf31408b20c0b48cb86af76866", + "sha256:b9d00268fcb9f66fbcc7cd9fe423741d90c75ee029a1d15c09b22d23253c0a44", + "sha256:bb01ba6b0d3f6c68b89fce7305080145d4877ad3acaed424bae4d4ee75faa950", + "sha256:c2aef4703f1f2ddc6df17519885dbfa3514929149d3ff900b73f45998f2532fa", + "sha256:c34dc4958b232ef6188c4318cb7b2c2d80521c9a56c52449f8f93ab7bc2a8a1c", + "sha256:c3630c3ef435c0a7c549ba170a0633a56e92629aeed0e707fec832dee313fb7a", + "sha256:c3d6a4d0619e09dcd61021debf7059955c2004fa29f48788a3dfaf9c9901a7cd", + "sha256:d15367ce87c8e9e09b0f989bfd72dc641bcd04ba091c68cd305312d00962addd", + "sha256:d2f9b69293c33aaa53d923032fe227feac867f81682f002ce33ffae978f0a9a9", + "sha256:e999f2d0e12eea01caeecb17b653f3713d758f6dcc770417cf29ef08d3931421", + "sha256:ea302f34477fda3f85560a06d9ebdc7fa41e82420e892fc50b577e35fc6a50b2", + "sha256:eaba923151d9deea315be1f3e2b31cc39a6d1d2f682f942905951f4e40200922", + "sha256:ef9612483cb35171d51d9173647eed5d0069eaa2ee812793a75373447d487aa4", + "sha256:f5315a2eb0239185af1bddb1abf472d877fede3cc8d143c6cddad37678293237", + "sha256:fa0ffcace9b3aa34d205d8130f7873fcfefcb6a4dd3dd705b0dab69af6712642", + "sha256:fc5471e1a54de15ef71c1bc6ebe80d4dc681ea600e68bfd1cbce40427f0b7578" + ], + "index": "pypi", + "markers": "python_version >= '3.6'", + "version": "==3.8.1" + }, "aionotify": { "hashes": [ "sha256:385e1becfaac2d9f4326673033d53912ef9565b6febdedbec593ee966df392c6", @@ -23,6 +102,14 @@ ], "version": "==0.2.0" }, + "aiosignal": { + "hashes": [ + "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc", + "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17" + ], + "markers": "python_version >= '3.7'", + "version": "==1.3.1" + }, "anyio": { "hashes": [ "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780", @@ -32,6 +119,14 @@ "markers": "python_version >= '3.7'", "version": "==3.7.1" }, + "async-timeout": { + "hashes": [ + "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", + "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028" + ], + "markers": "python_version >= '3.7'", + "version": "==4.0.3" + }, "attrs": { "hashes": [ "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", @@ -40,6 +135,14 @@ "markers": "python_version >= '3.7'", "version": "==23.2.0" }, + "charset-normalizer": { + "hashes": [ + "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845", + "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f" + ], + "markers": "python_full_version >= '3.6.0'", + "version": "==2.1.1" + }, "click": { "hashes": [ "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e", @@ -66,6 +169,153 @@ "markers": "python_version >= '3.7'", "version": "==0.99.1" }, + "frozenlist": { + "hashes": [ + "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7", + "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98", + "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad", + "sha256:0c250a29735d4f15321007fb02865f0e6b6a41a6b88f1f523ca1596ab5f50bd5", + "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae", + "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e", + "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a", + "sha256:1d0ce09d36d53bbbe566fe296965b23b961764c0bcf3ce2fa45f463745c04701", + "sha256:20b51fa3f588ff2fe658663db52a41a4f7aa6c04f6201449c6c7c476bd255c0d", + "sha256:23b2d7679b73fe0e5a4560b672a39f98dfc6f60df63823b0a9970525325b95f6", + "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6", + "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106", + "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75", + "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868", + "sha256:32453c1de775c889eb4e22f1197fe3bdfe457d16476ea407472b9442e6295f7a", + "sha256:3a670dc61eb0d0eb7080890c13de3066790f9049b47b0de04007090807c776b0", + "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1", + "sha256:410478a0c562d1a5bcc2f7ea448359fcb050ed48b3c6f6f4f18c313a9bdb1826", + "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec", + "sha256:48f6a4533887e189dae092f1cf981f2e3885175f7a0f33c91fb5b7b682b6bab6", + "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950", + "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19", + "sha256:55fdc093b5a3cb41d420884cdaf37a1e74c3c37a31f46e66286d9145d2063bd0", + "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8", + "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a", + "sha256:5a7d70357e7cee13f470c7883a063aae5fe209a493c57d86eb7f5a6f910fae09", + "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86", + "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c", + "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5", + "sha256:693945278a31f2086d9bf3df0fe8254bbeaef1fe71e1351c3bd730aa7d31c41b", + "sha256:6db4667b187a6742b33afbbaf05a7bc551ffcf1ced0000a571aedbb4aa42fc7b", + "sha256:6eb73fa5426ea69ee0e012fb59cdc76a15b1283d6e32e4f8dc4482ec67d1194d", + "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0", + "sha256:7268252af60904bf52c26173cbadc3a071cece75f873705419c8681f24d3edea", + "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776", + "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a", + "sha256:82e8211d69a4f4bc360ea22cd6555f8e61a1bd211d1d5d39d3d228b48c83a897", + "sha256:89aa2c2eeb20957be2d950b85974b30a01a762f3308cd02bb15e1ad632e22dc7", + "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09", + "sha256:96ec70beabbd3b10e8bfe52616a13561e58fe84c0101dd031dc78f250d5128b9", + "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe", + "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd", + "sha256:9d3e0c25a2350080e9319724dede4f31f43a6c9779be48021a7f4ebde8b2d742", + "sha256:a06339f38e9ed3a64e4c4e43aec7f59084033647f908e4259d279a52d3757d09", + "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0", + "sha256:a7496bfe1da7fb1a4e1cc23bb67c58fab69311cc7d32b5a99c2007b4b2a0e932", + "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1", + "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a", + "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49", + "sha256:b7e3ed87d4138356775346e6845cccbe66cd9e207f3cd11d2f0b9fd13681359d", + "sha256:b7f2f9f912dca3934c1baec2e4585a674ef16fe00218d833856408c48d5beee7", + "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480", + "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89", + "sha256:bfa4a17e17ce9abf47a74ae02f32d014c5e9404b6d9ac7f729e01562bbee601e", + "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b", + "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82", + "sha256:c6321c9efe29975232da3bd0af0ad216800a47e93d763ce64f291917a381b8eb", + "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068", + "sha256:c99169d4ff810155ca50b4da3b075cbde79752443117d89429595c2e8e37fed8", + "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b", + "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb", + "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2", + "sha256:dca69045298ce5c11fd539682cff879cc1e664c245d1c64da929813e54241d11", + "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b", + "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc", + "sha256:e6a20a581f9ce92d389a8c7d7c3dd47c81fd5d6e655c8dddf341e14aa48659d0", + "sha256:e7004be74cbb7d9f34553a5ce5fb08be14fb33bc86f332fb71cbe5216362a497", + "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17", + "sha256:edb678da49d9f72c9f6c609fbe41a5dfb9a9282f9e6a2253d5a91e0fc382d7c0", + "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2", + "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439", + "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5", + "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac", + "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825", + "sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887", + "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced", + "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74" + ], + "markers": "python_version >= '3.8'", + "version": "==1.4.1" + }, + "greenlet": { + "hashes": [ + "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67", + "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6", + "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257", + "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4", + "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676", + "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61", + "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc", + "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca", + "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7", + "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728", + "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305", + "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6", + "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379", + "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414", + "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04", + "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a", + "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf", + "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491", + "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559", + "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e", + "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274", + "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb", + "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b", + "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9", + "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b", + "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be", + "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506", + "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405", + "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113", + "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f", + "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5", + "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230", + "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d", + "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f", + "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a", + "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e", + "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61", + "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6", + "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d", + "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71", + "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22", + "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2", + "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3", + "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067", + "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc", + "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881", + "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3", + "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e", + "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac", + "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53", + "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0", + "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b", + "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83", + "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41", + "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c", + "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf", + "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da", + "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33" + ], + "markers": "python_version >= '3' and platform_machine == 'aarch64' or (platform_machine == 'ppc64le' or (platform_machine == 'x86_64' or (platform_machine == 'amd64' or (platform_machine == 'AMD64' or (platform_machine == 'win32' or platform_machine == 'WIN32')))))", + "version": "==3.0.3" + }, "h11": { "hashes": [ "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", @@ -93,65 +343,161 @@ }, "msgpack": { "hashes": [ - "sha256:04ad6069c86e531682f9e1e71b71c1c3937d6014a7c3e9edd2aa81ad58842862", - "sha256:0bfdd914e55e0d2c9e1526de210f6fe8ffe9705f2b1dfcc4aecc92a4cb4b533d", - "sha256:1dc93e8e4653bdb5910aed79f11e165c85732067614f180f70534f056da97db3", - "sha256:1e2d69948e4132813b8d1131f29f9101bc2c915f26089a6d632001a5c1349672", - "sha256:235a31ec7db685f5c82233bddf9858748b89b8119bf4538d514536c485c15fe0", - "sha256:27dcd6f46a21c18fa5e5deed92a43d4554e3df8d8ca5a47bf0615d6a5f39dbc9", - "sha256:28efb066cde83c479dfe5a48141a53bc7e5f13f785b92ddde336c716663039ee", - "sha256:3476fae43db72bd11f29a5147ae2f3cb22e2f1a91d575ef130d2bf49afd21c46", - "sha256:36e17c4592231a7dbd2ed09027823ab295d2791b3b1efb2aee874b10548b7524", - "sha256:384d779f0d6f1b110eae74cb0659d9aa6ff35aaf547b3955abf2ab4c901c4819", - "sha256:38949d30b11ae5f95c3c91917ee7a6b239f5ec276f271f28638dec9156f82cfc", - "sha256:3967e4ad1aa9da62fd53e346ed17d7b2e922cba5ab93bdd46febcac39be636fc", - "sha256:3e7bf4442b310ff154b7bb9d81eb2c016b7d597e364f97d72b1acc3817a0fdc1", - "sha256:3f0c8c6dfa6605ab8ff0611995ee30d4f9fcff89966cf562733b4008a3d60d82", - "sha256:484ae3240666ad34cfa31eea7b8c6cd2f1fdaae21d73ce2974211df099a95d81", - "sha256:4a7b4f35de6a304b5533c238bee86b670b75b03d31b7797929caa7a624b5dda6", - "sha256:4cb14ce54d9b857be9591ac364cb08dc2d6a5c4318c1182cb1d02274029d590d", - "sha256:4e71bc4416de195d6e9b4ee93ad3f2f6b2ce11d042b4d7a7ee00bbe0358bd0c2", - "sha256:52700dc63a4676669b341ba33520f4d6e43d3ca58d422e22ba66d1736b0a6e4c", - "sha256:572efc93db7a4d27e404501975ca6d2d9775705c2d922390d878fcf768d92c87", - "sha256:576eb384292b139821c41995523654ad82d1916da6a60cff129c715a6223ea84", - "sha256:5b0bf0effb196ed76b7ad883848143427a73c355ae8e569fa538365064188b8e", - "sha256:5b6ccc0c85916998d788b295765ea0e9cb9aac7e4a8ed71d12e7d8ac31c23c95", - "sha256:5ed82f5a7af3697b1c4786053736f24a0efd0a1b8a130d4c7bfee4b9ded0f08f", - "sha256:6d4c80667de2e36970ebf74f42d1088cc9ee7ef5f4e8c35eee1b40eafd33ca5b", - "sha256:730076207cb816138cf1af7f7237b208340a2c5e749707457d70705715c93b93", - "sha256:7687e22a31e976a0e7fc99c2f4d11ca45eff652a81eb8c8085e9609298916dcf", - "sha256:822ea70dc4018c7e6223f13affd1c5c30c0f5c12ac1f96cd8e9949acddb48a61", - "sha256:84b0daf226913133f899ea9b30618722d45feffa67e4fe867b0b5ae83a34060c", - "sha256:85765fdf4b27eb5086f05ac0491090fc76f4f2b28e09d9350c31aac25a5aaff8", - "sha256:8dd178c4c80706546702c59529ffc005681bd6dc2ea234c450661b205445a34d", - "sha256:8f5b234f567cf76ee489502ceb7165c2a5cecec081db2b37e35332b537f8157c", - "sha256:98bbd754a422a0b123c66a4c341de0474cad4a5c10c164ceed6ea090f3563db4", - "sha256:993584fc821c58d5993521bfdcd31a4adf025c7d745bbd4d12ccfecf695af5ba", - "sha256:a40821a89dc373d6427e2b44b572efc36a2778d3f543299e2f24eb1a5de65415", - "sha256:b291f0ee7961a597cbbcc77709374087fa2a9afe7bdb6a40dbbd9b127e79afee", - "sha256:b573a43ef7c368ba4ea06050a957c2a7550f729c31f11dd616d2ac4aba99888d", - "sha256:b610ff0f24e9f11c9ae653c67ff8cc03c075131401b3e5ef4b82570d1728f8a9", - "sha256:bdf38ba2d393c7911ae989c3bbba510ebbcdf4ecbdbfec36272abe350c454075", - "sha256:bfef2bb6ef068827bbd021017a107194956918ab43ce4d6dc945ffa13efbc25f", - "sha256:cab3db8bab4b7e635c1c97270d7a4b2a90c070b33cbc00c99ef3f9be03d3e1f7", - "sha256:cb70766519500281815dfd7a87d3a178acf7ce95390544b8c90587d76b227681", - "sha256:cca1b62fe70d761a282496b96a5e51c44c213e410a964bdffe0928e611368329", - "sha256:ccf9a39706b604d884d2cb1e27fe973bc55f2890c52f38df742bc1d79ab9f5e1", - "sha256:dc43f1ec66eb8440567186ae2f8c447d91e0372d793dfe8c222aec857b81a8cf", - "sha256:dd632777ff3beaaf629f1ab4396caf7ba0bdd075d948a69460d13d44357aca4c", - "sha256:e45ae4927759289c30ccba8d9fdce62bb414977ba158286b5ddaf8df2cddb5c5", - "sha256:e50ebce52f41370707f1e21a59514e3375e3edd6e1832f5e5235237db933c98b", - "sha256:ebbbba226f0a108a7366bf4b59bf0f30a12fd5e75100c630267d94d7f0ad20e5", - "sha256:ec79ff6159dffcc30853b2ad612ed572af86c92b5168aa3fc01a67b0fa40665e", - "sha256:f0936e08e0003f66bfd97e74ee530427707297b0d0361247e9b4f59ab78ddc8b", - "sha256:f26a07a6e877c76a88e3cecac8531908d980d3d5067ff69213653649ec0f60ad", - "sha256:f64e376cd20d3f030190e8c32e1c64582eba56ac6dc7d5b0b49a9d44021b52fd", - "sha256:f6ffbc252eb0d229aeb2f9ad051200668fc3a9aaa8994e49f0cb2ffe2b7867e7", - "sha256:f9a7c509542db4eceed3dcf21ee5267ab565a83555c9b88a8109dcecc4709002", - "sha256:ff1d0899f104f3921d94579a5638847f783c9b04f2d5f229392ca77fba5b82fc" + "sha256:00e073efcba9ea99db5acef3959efa45b52bc67b61b00823d2a1a6944bf45982", + "sha256:0726c282d188e204281ebd8de31724b7d749adebc086873a59efb8cf7ae27df3", + "sha256:0ceea77719d45c839fd73abcb190b8390412a890df2f83fb8cf49b2a4b5c2f40", + "sha256:114be227f5213ef8b215c22dde19532f5da9652e56e8ce969bf0a26d7c419fee", + "sha256:13577ec9e247f8741c84d06b9ece5f654920d8365a4b636ce0e44f15e07ec693", + "sha256:1876b0b653a808fcd50123b953af170c535027bf1d053b59790eebb0aeb38950", + "sha256:1ab0bbcd4d1f7b6991ee7c753655b481c50084294218de69365f8f1970d4c151", + "sha256:1cce488457370ffd1f953846f82323cb6b2ad2190987cd4d70b2713e17268d24", + "sha256:26ee97a8261e6e35885c2ecd2fd4a6d38252246f94a2aec23665a4e66d066305", + "sha256:3528807cbbb7f315bb81959d5961855e7ba52aa60a3097151cb21956fbc7502b", + "sha256:374a8e88ddab84b9ada695d255679fb99c53513c0a51778796fcf0944d6c789c", + "sha256:376081f471a2ef24828b83a641a02c575d6103a3ad7fd7dade5486cad10ea659", + "sha256:3923a1778f7e5ef31865893fdca12a8d7dc03a44b33e2a5f3295416314c09f5d", + "sha256:4916727e31c28be8beaf11cf117d6f6f188dcc36daae4e851fee88646f5b6b18", + "sha256:493c5c5e44b06d6c9268ce21b302c9ca055c1fd3484c25ba41d34476c76ee746", + "sha256:505fe3d03856ac7d215dbe005414bc28505d26f0c128906037e66d98c4e95868", + "sha256:5845fdf5e5d5b78a49b826fcdc0eb2e2aa7191980e3d2cfd2a30303a74f212e2", + "sha256:5c330eace3dd100bdb54b5653b966de7f51c26ec4a7d4e87132d9b4f738220ba", + "sha256:5dbf059fb4b7c240c873c1245ee112505be27497e90f7c6591261c7d3c3a8228", + "sha256:5e390971d082dba073c05dbd56322427d3280b7cc8b53484c9377adfbae67dc2", + "sha256:5fbb160554e319f7b22ecf530a80a3ff496d38e8e07ae763b9e82fadfe96f273", + "sha256:64d0fcd436c5683fdd7c907eeae5e2cbb5eb872fafbc03a43609d7941840995c", + "sha256:69284049d07fce531c17404fcba2bb1df472bc2dcdac642ae71a2d079d950653", + "sha256:6a0e76621f6e1f908ae52860bdcb58e1ca85231a9b0545e64509c931dd34275a", + "sha256:73ee792784d48aa338bba28063e19a27e8d989344f34aad14ea6e1b9bd83f596", + "sha256:74398a4cf19de42e1498368c36eed45d9528f5fd0155241e82c4082b7e16cffd", + "sha256:7938111ed1358f536daf311be244f34df7bf3cdedb3ed883787aca97778b28d8", + "sha256:82d92c773fbc6942a7a8b520d22c11cfc8fd83bba86116bfcf962c2f5c2ecdaa", + "sha256:83b5c044f3eff2a6534768ccfd50425939e7a8b5cf9a7261c385de1e20dcfc85", + "sha256:8db8e423192303ed77cff4dce3a4b88dbfaf43979d280181558af5e2c3c71afc", + "sha256:9517004e21664f2b5a5fd6333b0731b9cf0817403a941b393d89a2f1dc2bd836", + "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3", + "sha256:99881222f4a8c2f641f25703963a5cefb076adffd959e0558dc9f803a52d6a58", + "sha256:9ee32dcb8e531adae1f1ca568822e9b3a738369b3b686d1477cbc643c4a9c128", + "sha256:a22e47578b30a3e199ab067a4d43d790249b3c0587d9a771921f86250c8435db", + "sha256:b5505774ea2a73a86ea176e8a9a4a7c8bf5d521050f0f6f8426afe798689243f", + "sha256:bd739c9251d01e0279ce729e37b39d49a08c0420d3fee7f2a4968c0576678f77", + "sha256:d16a786905034e7e34098634b184a7d81f91d4c3d246edc6bd7aefb2fd8ea6ad", + "sha256:d3420522057ebab1728b21ad473aa950026d07cb09da41103f8e597dfbfaeb13", + "sha256:d56fd9f1f1cdc8227d7b7918f55091349741904d9520c65f0139a9755952c9e8", + "sha256:d661dc4785affa9d0edfdd1e59ec056a58b3dbb9f196fa43587f3ddac654ac7b", + "sha256:dfe1f0f0ed5785c187144c46a292b8c34c1295c01da12e10ccddfc16def4448a", + "sha256:e1dd7839443592d00e96db831eddb4111a2a81a46b028f0facd60a09ebbdd543", + "sha256:e2872993e209f7ed04d963e4b4fbae72d034844ec66bc4ca403329db2074377b", + "sha256:e2f879ab92ce502a1e65fce390eab619774dda6a6ff719718069ac94084098ce", + "sha256:e3aa7e51d738e0ec0afbed661261513b38b3014754c9459508399baf14ae0c9d", + "sha256:e532dbd6ddfe13946de050d7474e3f5fb6ec774fbb1a188aaf469b08cf04189a", + "sha256:e6b7842518a63a9f17107eb176320960ec095a8ee3b4420b5f688e24bf50c53c", + "sha256:e75753aeda0ddc4c28dce4c32ba2f6ec30b1b02f6c0b14e547841ba5b24f753f", + "sha256:eadb9f826c138e6cf3c49d6f8de88225a3c0ab181a9b4ba792e006e5292d150e", + "sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011", + "sha256:ef254a06bcea461e65ff0373d8a0dd1ed3aa004af48839f002a0c994a6f72d04", + "sha256:f3709997b228685fe53e8c433e2df9f0cdb5f4542bd5114ed17ac3c0129b0480", + "sha256:f51bab98d52739c50c56658cc303f190785f9a2cd97b823357e7aeae54c8f68a", + "sha256:f9904e24646570539a8950400602d66d2b2c492b9010ea7e965025cb71d0c86d", + "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d" ], "markers": "platform_system != 'Windows'", - "version": "==1.0.7" + "version": "==1.0.8" + }, + "multidict": { + "hashes": [ + "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556", + "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c", + "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29", + "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b", + "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8", + "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7", + "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd", + "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40", + "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6", + "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3", + "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c", + "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9", + "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5", + "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae", + "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442", + "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9", + "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc", + "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c", + "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea", + "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5", + "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50", + "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182", + "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453", + "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e", + "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600", + "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733", + "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda", + "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241", + "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461", + "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e", + "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e", + "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b", + "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e", + "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7", + "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386", + "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd", + "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9", + "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf", + "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee", + "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5", + "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a", + "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271", + "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54", + "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4", + "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496", + "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb", + "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319", + "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3", + "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f", + "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527", + "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed", + "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604", + "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef", + "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8", + "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5", + "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5", + "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626", + "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c", + "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d", + "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c", + "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc", + "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc", + "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b", + "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38", + "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450", + "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1", + "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f", + "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3", + "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755", + "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226", + "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a", + "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046", + "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf", + "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479", + "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e", + "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1", + "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a", + "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83", + "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929", + "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93", + "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a", + "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c", + "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44", + "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89", + "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba", + "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e", + "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da", + "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24", + "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423", + "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef" + ], + "markers": "python_version >= '3.7'", + "version": "==6.0.5" }, "numpy": { "hashes": [ @@ -182,6 +528,7 @@ }, "opentrons": { "editable": true, + "markers": "python_version >= '3.8'", "path": "../api" }, "opentrons-hardware": { @@ -193,15 +540,16 @@ }, "opentrons-shared-data": { "editable": true, + "markers": "python_version >= '3.8'", "path": "../shared-data/python" }, "packaging": { "hashes": [ - "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", - "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" + "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", + "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9" ], "markers": "python_version >= '3.7'", - "version": "==23.2" + "version": "==24.0" }, "paho-mqtt": { "hashes": [ @@ -333,19 +681,19 @@ }, "setuptools": { "hashes": [ - "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05", - "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78" + "sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987", + "sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32" ], "markers": "python_version >= '3.8'", - "version": "==69.0.3" + "version": "==69.5.1" }, "sniffio": { "hashes": [ - "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101", - "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384" + "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", + "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" ], "markers": "python_version >= '3.7'", - "version": "==1.3.0" + "version": "==1.3.1" }, "sqlalchemy": { "hashes": [ @@ -417,12 +765,12 @@ }, "typing-extensions": { "hashes": [ - "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", - "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0", + "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.9.0" + "version": "==4.11.0" }, "uvicorn": { "hashes": [ @@ -518,6 +866,102 @@ "markers": "python_full_version >= '3.7.0'", "version": "==1.2.0" }, + "yarl": { + "hashes": [ + "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51", + "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce", + "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559", + "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0", + "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81", + "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc", + "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4", + "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c", + "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130", + "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136", + "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e", + "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec", + "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7", + "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1", + "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455", + "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099", + "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129", + "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10", + "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142", + "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98", + "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa", + "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7", + "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525", + "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c", + "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9", + "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c", + "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8", + "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b", + "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf", + "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23", + "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd", + "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27", + "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f", + "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece", + "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434", + "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec", + "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff", + "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78", + "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d", + "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863", + "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53", + "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31", + "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15", + "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5", + "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b", + "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57", + "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3", + "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1", + "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f", + "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad", + "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c", + "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7", + "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2", + "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b", + "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2", + "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b", + "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9", + "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be", + "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e", + "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984", + "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4", + "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074", + "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2", + "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392", + "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91", + "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541", + "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf", + "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572", + "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66", + "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575", + "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14", + "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5", + "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1", + "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e", + "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551", + "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17", + "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead", + "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0", + "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe", + "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234", + "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0", + "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7", + "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34", + "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42", + "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385", + "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78", + "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be", + "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958", + "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749", + "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec" + ], + "markers": "python_version >= '3.7'", + "version": "==1.9.4" + }, "zipp": { "hashes": [ "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3", @@ -594,11 +1038,11 @@ }, "charset-normalizer": { "hashes": [ - "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597", - "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df" + "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845", + "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f" ], - "markers": "python_version >= '3'", - "version": "==2.0.12" + "markers": "python_full_version >= '3.6.0'", + "version": "==2.1.1" }, "click": { "hashes": [ @@ -622,61 +1066,61 @@ "toml" ], "hashes": [ - "sha256:0193657651f5399d433c92f8ae264aff31fc1d066deee4b831549526433f3f61", - "sha256:02f2edb575d62172aa28fe00efe821ae31f25dc3d589055b3fb64d51e52e4ab1", - "sha256:0491275c3b9971cdbd28a4595c2cb5838f08036bca31765bad5e17edf900b2c7", - "sha256:077d366e724f24fc02dbfe9d946534357fda71af9764ff99d73c3c596001bbd7", - "sha256:10e88e7f41e6197ea0429ae18f21ff521d4f4490aa33048f6c6f94c6045a6a75", - "sha256:18e961aa13b6d47f758cc5879383d27b5b3f3dcd9ce8cdbfdc2571fe86feb4dd", - "sha256:1a78b656a4d12b0490ca72651fe4d9f5e07e3c6461063a9b6265ee45eb2bdd35", - "sha256:1ed4b95480952b1a26d863e546fa5094564aa0065e1e5f0d4d0041f293251d04", - "sha256:23b27b8a698e749b61809fb637eb98ebf0e505710ec46a8aa6f1be7dc0dc43a6", - "sha256:23f5881362dcb0e1a92b84b3c2809bdc90db892332daab81ad8f642d8ed55042", - "sha256:32a8d985462e37cfdab611a6f95b09d7c091d07668fdc26e47a725ee575fe166", - "sha256:3468cc8720402af37b6c6e7e2a9cdb9f6c16c728638a2ebc768ba1ef6f26c3a1", - "sha256:379d4c7abad5afbe9d88cc31ea8ca262296480a86af945b08214eb1a556a3e4d", - "sha256:3cacfaefe6089d477264001f90f55b7881ba615953414999c46cc9713ff93c8c", - "sha256:3e3424c554391dc9ef4a92ad28665756566a28fecf47308f91841f6c49288e66", - "sha256:46342fed0fff72efcda77040b14728049200cbba1279e0bf1188f1f2078c1d70", - "sha256:536d609c6963c50055bab766d9951b6c394759190d03311f3e9fcf194ca909e1", - "sha256:5d6850e6e36e332d5511a48a251790ddc545e16e8beaf046c03985c69ccb2676", - "sha256:6008adeca04a445ea6ef31b2cbaf1d01d02986047606f7da266629afee982630", - "sha256:64e723ca82a84053dd7bfcc986bdb34af8d9da83c521c19d6b472bc6880e191a", - "sha256:6b00e21f86598b6330f0019b40fb397e705135040dbedc2ca9a93c7441178e74", - "sha256:6d224f0c4c9c98290a6990259073f496fcec1b5cc613eecbd22786d398ded3ad", - "sha256:6dceb61d40cbfcf45f51e59933c784a50846dc03211054bd76b421a713dcdf19", - "sha256:7ac8f8eb153724f84885a1374999b7e45734bf93a87d8df1e7ce2146860edef6", - "sha256:85ccc5fa54c2ed64bd91ed3b4a627b9cce04646a659512a051fa82a92c04a448", - "sha256:869b5046d41abfea3e381dd143407b0d29b8282a904a19cb908fa24d090cc018", - "sha256:8bdb0285a0202888d19ec6b6d23d5990410decb932b709f2b0dfe216d031d218", - "sha256:8dfc5e195bbef80aabd81596ef52a1277ee7143fe419efc3c4d8ba2754671756", - "sha256:8e738a492b6221f8dcf281b67129510835461132b03024830ac0e554311a5c54", - "sha256:918440dea04521f499721c039863ef95433314b1db00ff826a02580c1f503e45", - "sha256:9641e21670c68c7e57d2053ddf6c443e4f0a6e18e547e86af3fad0795414a628", - "sha256:9d2f9d4cc2a53b38cabc2d6d80f7f9b7e3da26b2f53d48f05876fef7956b6968", - "sha256:a07f61fc452c43cd5328b392e52555f7d1952400a1ad09086c4a8addccbd138d", - "sha256:a3277f5fa7483c927fe3a7b017b39351610265308f5267ac6d4c2b64cc1d8d25", - "sha256:a4a3907011d39dbc3e37bdc5df0a8c93853c369039b59efa33a7b6669de04c60", - "sha256:aeb2c2688ed93b027eb0d26aa188ada34acb22dceea256d76390eea135083950", - "sha256:b094116f0b6155e36a304ff912f89bbb5067157aff5f94060ff20bbabdc8da06", - "sha256:b8ffb498a83d7e0305968289441914154fb0ef5d8b3157df02a90c6695978295", - "sha256:b9bb62fac84d5f2ff523304e59e5c439955fb3b7f44e3d7b2085184db74d733b", - "sha256:c61f66d93d712f6e03369b6a7769233bfda880b12f417eefdd4f16d1deb2fc4c", - "sha256:ca6e61dc52f601d1d224526360cdeab0d0712ec104a2ce6cc5ccef6ed9a233bc", - "sha256:ca7b26a5e456a843b9b6683eada193fc1f65c761b3a473941efe5a291f604c74", - "sha256:d12c923757de24e4e2110cf8832d83a886a4cf215c6e61ed506006872b43a6d1", - "sha256:d17bbc946f52ca67adf72a5ee783cd7cd3477f8f8796f59b4974a9b59cacc9ee", - "sha256:dfd1e1b9f0898817babf840b77ce9fe655ecbe8b1b327983df485b30df8cc011", - "sha256:e0860a348bf7004c812c8368d1fc7f77fe8e4c095d661a579196a9533778e156", - "sha256:f2f5968608b1fe2a1d00d01ad1017ee27efd99b3437e08b83ded9b7af3f6f766", - "sha256:f3771b23bb3675a06f5d885c3630b1d01ea6cac9e84a01aaf5508706dba546c5", - "sha256:f68ef3660677e6624c8cace943e4765545f8191313a07288a53d3da188bd8581", - "sha256:f86f368e1c7ce897bf2457b9eb61169a44e2ef797099fb5728482b8d69f3f016", - "sha256:f90515974b39f4dea2f27c0959688621b46d96d5a626cf9c53dbc653a895c05c", - "sha256:fe558371c1bdf3b8fa03e097c523fb9645b8730399c14fe7721ee9c9e2a545d3" + "sha256:00838a35b882694afda09f85e469c96367daa3f3f2b097d846a7216993d37f4c", + "sha256:0513b9508b93da4e1716744ef6ebc507aff016ba115ffe8ecff744d1322a7b63", + "sha256:09c3255458533cb76ef55da8cc49ffab9e33f083739c8bd4f58e79fecfe288f7", + "sha256:09ef9199ed6653989ebbcaacc9b62b514bb63ea2f90256e71fea3ed74bd8ff6f", + "sha256:09fa497a8ab37784fbb20ab699c246053ac294d13fc7eb40ec007a5043ec91f8", + "sha256:0f9f50e7ef2a71e2fae92774c99170eb8304e3fdf9c8c3c7ae9bab3e7229c5cf", + "sha256:137eb07173141545e07403cca94ab625cc1cc6bc4c1e97b6e3846270e7e1fea0", + "sha256:1f384c3cc76aeedce208643697fb3e8437604b512255de6d18dae3f27655a384", + "sha256:201bef2eea65e0e9c56343115ba3814e896afe6d36ffd37bab783261db430f76", + "sha256:38dd60d7bf242c4ed5b38e094baf6401faa114fc09e9e6632374388a404f98e7", + "sha256:3b799445b9f7ee8bf299cfaed6f5b226c0037b74886a4e11515e569b36fe310d", + "sha256:3ea79bb50e805cd6ac058dfa3b5c8f6c040cb87fe83de10845857f5535d1db70", + "sha256:40209e141059b9370a2657c9b15607815359ab3ef9918f0196b6fccce8d3230f", + "sha256:41c9c5f3de16b903b610d09650e5e27adbfa7f500302718c9ffd1c12cf9d6818", + "sha256:54eb8d1bf7cacfbf2a3186019bcf01d11c666bd495ed18717162f7eb1e9dd00b", + "sha256:598825b51b81c808cb6f078dcb972f96af96b078faa47af7dfcdf282835baa8d", + "sha256:5fc1de20b2d4a061b3df27ab9b7c7111e9a710f10dc2b84d33a4ab25065994ec", + "sha256:623512f8ba53c422fcfb2ce68362c97945095b864cda94a92edbaf5994201083", + "sha256:690db6517f09336559dc0b5f55342df62370a48f5469fabf502db2c6d1cffcd2", + "sha256:69eb372f7e2ece89f14751fbcbe470295d73ed41ecd37ca36ed2eb47512a6ab9", + "sha256:73bfb9c09951125d06ee473bed216e2c3742f530fc5acc1383883125de76d9cd", + "sha256:742a76a12aa45b44d236815d282b03cfb1de3b4323f3e4ec933acfae08e54ade", + "sha256:7c95949560050d04d46b919301826525597f07b33beba6187d04fa64d47ac82e", + "sha256:8130a2aa2acb8788e0b56938786c33c7c98562697bf9f4c7d6e8e5e3a0501e4a", + "sha256:8a2b2b78c78293782fd3767d53e6474582f62443d0504b1554370bde86cc8227", + "sha256:8ce1415194b4a6bd0cdcc3a1dfbf58b63f910dcb7330fe15bdff542c56949f87", + "sha256:9ca28a302acb19b6af89e90f33ee3e1906961f94b54ea37de6737b7ca9d8827c", + "sha256:a4cdc86d54b5da0df6d3d3a2f0b710949286094c3a6700c21e9015932b81447e", + "sha256:aa5b1c1bfc28384f1f53b69a023d789f72b2e0ab1b3787aae16992a7ca21056c", + "sha256:aadacf9a2f407a4688d700e4ebab33a7e2e408f2ca04dbf4aef17585389eff3e", + "sha256:ae71e7ddb7a413dd60052e90528f2f65270aad4b509563af6d03d53e979feafd", + "sha256:b14706df8b2de49869ae03a5ccbc211f4041750cd4a66f698df89d44f4bd30ec", + "sha256:b1a93009cb80730c9bca5d6d4665494b725b6e8e157c1cb7f2db5b4b122ea562", + "sha256:b2991665420a803495e0b90a79233c1433d6ed77ef282e8e152a324bbbc5e0c8", + "sha256:b2c5edc4ac10a7ef6605a966c58929ec6c1bd0917fb8c15cb3363f65aa40e677", + "sha256:b4d33f418f46362995f1e9d4f3a35a1b6322cb959c31d88ae56b0298e1c22357", + "sha256:b91cbc4b195444e7e258ba27ac33769c41b94967919f10037e6355e998af255c", + "sha256:c74880fc64d4958159fbd537a091d2a585448a8f8508bf248d72112723974cbd", + "sha256:c901df83d097649e257e803be22592aedfd5182f07b3cc87d640bbb9afd50f49", + "sha256:cac99918c7bba15302a2d81f0312c08054a3359eaa1929c7e4b26ebe41e9b286", + "sha256:cc4f1358cb0c78edef3ed237ef2c86056206bb8d9140e73b6b89fbcfcbdd40e1", + "sha256:ccd341521be3d1b3daeb41960ae94a5e87abe2f46f17224ba5d6f2b8398016cf", + "sha256:ce4b94265ca988c3f8e479e741693d143026632672e3ff924f25fab50518dd51", + "sha256:cf271892d13e43bc2b51e6908ec9a6a5094a4df1d8af0bfc360088ee6c684409", + "sha256:d5ae728ff3b5401cc320d792866987e7e7e880e6ebd24433b70a33b643bb0384", + "sha256:d71eec7d83298f1af3326ce0ff1d0ea83c7cb98f72b577097f9083b20bdaf05e", + "sha256:d898fe162d26929b5960e4e138651f7427048e72c853607f2b200909794ed978", + "sha256:d89d7b2974cae412400e88f35d86af72208e1ede1a541954af5d944a8ba46c57", + "sha256:dfa8fe35a0bb90382837b238fff375de15f0dcdb9ae68ff85f7a63649c98527e", + "sha256:e0be5efd5127542ef31f165de269f77560d6cdef525fffa446de6f7e9186cfb2", + "sha256:fdfafb32984684eb03c2d83e1e51f64f0906b11e64482df3c5db936ce3839d48", + "sha256:ff7687ca3d7028d8a5f0ebae95a6e4827c5616b31a4ee1192bdfde697db110d4" ], "markers": "python_version >= '3.8'", - "version": "==7.4.1" + "version": "==7.4.4" }, "decoy": { "hashes": [ @@ -703,11 +1147,11 @@ }, "execnet": { "hashes": [ - "sha256:88256416ae766bc9e8895c76a87928c0012183da3cc4fc18016e6f050e025f41", - "sha256:cc59bc4423742fd71ad227122eb0dd44db51efb3dc4095b45ac9a08c770096af" + "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", + "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3" ], - "markers": "python_version >= '3.7'", - "version": "==2.0.2" + "markers": "python_version >= '3.8'", + "version": "==2.1.1" }, "flake8": { "hashes": [ @@ -764,11 +1208,11 @@ }, "httpcore": { "hashes": [ - "sha256:096cc05bca73b8e459a1fc3dcf585148f63e534eae4339559c9b8a8d6399acc7", - "sha256:9fc092e4799b26174648e54b74ed5f683132a464e95643b226e00c2ed2fa6535" + "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61", + "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5" ], "markers": "python_version >= '3.8'", - "version": "==1.0.2" + "version": "==1.0.5" }, "httpx": { "hashes": [ @@ -812,14 +1256,6 @@ "markers": "python_version >= '3.7'", "version": "==4.17.3" }, - "jsonschema-specifications": { - "hashes": [ - "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc", - "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c" - ], - "markers": "python_version >= '3.8'", - "version": "==2023.12.1" - }, "mccabe": { "hashes": [ "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", @@ -879,13 +1315,18 @@ "markers": "python_version >= '3.5'", "version": "==1.0.0" }, + "opentrons-shared-data": { + "editable": true, + "markers": "python_version >= '3.8'", + "path": "../shared-data/python" + }, "packaging": { "hashes": [ - "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", - "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" + "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", + "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9" ], "markers": "python_version >= '3.7'", - "version": "==23.2" + "version": "==24.0" }, "paho-mqtt": { "hashes": [ @@ -909,6 +1350,10 @@ "markers": "python_version >= '2.6'", "version": "==6.0.0" }, + "performance-metrics": { + "editable": true, + "file": "../performance-metrics" + }, "platformdirs": { "hashes": [ "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068", @@ -941,6 +1386,49 @@ "markers": "python_version >= '3.8'", "version": "==2.11.1" }, + "pydantic": { + "hashes": [ + "sha256:0fe8a415cea8f340e7a9af9c54fc71a649b43e8ca3cc732986116b3cb135d303", + "sha256:1289c180abd4bd4555bb927c42ee42abc3aee02b0fb2d1223fb7c6e5bef87dbe", + "sha256:1eb2085c13bce1612da8537b2d90f549c8cbb05c67e8f22854e201bde5d98a47", + "sha256:2031de0967c279df0d8a1c72b4ffc411ecd06bac607a212892757db7462fc494", + "sha256:2a7bac939fa326db1ab741c9d7f44c565a1d1e80908b3797f7f81a4f86bc8d33", + "sha256:2d5a58feb9a39f481eda4d5ca220aa8b9d4f21a41274760b9bc66bfd72595b86", + "sha256:2f9a6fab5f82ada41d56b0602606a5506aab165ca54e52bc4545028382ef1c5d", + "sha256:2fcfb5296d7877af406ba1547dfde9943b1256d8928732267e2653c26938cd9c", + "sha256:549a8e3d81df0a85226963611950b12d2d334f214436a19537b2efed61b7639a", + "sha256:598da88dfa127b666852bef6d0d796573a8cf5009ffd62104094a4fe39599565", + "sha256:5d1197e462e0364906cbc19681605cb7c036f2475c899b6f296104ad42b9f5fb", + "sha256:69328e15cfda2c392da4e713443c7dbffa1505bc9d566e71e55abe14c97ddc62", + "sha256:6a9dfa722316f4acf4460afdf5d41d5246a80e249c7ff475c43a3a1e9d75cf62", + "sha256:6b30bcb8cbfccfcf02acb8f1a261143fab622831d9c0989707e0e659f77a18e0", + "sha256:6c076be61cd0177a8433c0adcb03475baf4ee91edf5a4e550161ad57fc90f523", + "sha256:771735dc43cf8383959dc9b90aa281f0b6092321ca98677c5fb6125a6f56d58d", + "sha256:795e34e6cc065f8f498c89b894a3c6da294a936ee71e644e4bd44de048af1405", + "sha256:87afda5539d5140cb8ba9e8b8c8865cb5b1463924d38490d73d3ccfd80896b3f", + "sha256:8fb2aa3ab3728d950bcc885a2e9eff6c8fc40bc0b7bb434e555c215491bcf48b", + "sha256:a1fcb59f2f355ec350073af41d927bf83a63b50e640f4dbaa01053a28b7a7718", + "sha256:a5e7add47a5b5a40c49b3036d464e3c7802f8ae0d1e66035ea16aa5b7a3923ed", + "sha256:a73f489aebd0c2121ed974054cb2759af8a9f747de120acd2c3394cf84176ccb", + "sha256:ab26038b8375581dc832a63c948f261ae0aa21f1d34c1293469f135fa92972a5", + "sha256:b0d191db0f92dfcb1dec210ca244fdae5cbe918c6050b342d619c09d31eea0cc", + "sha256:b749a43aa51e32839c9d71dc67eb1e4221bb04af1033a32e3923d46f9effa942", + "sha256:b7ccf02d7eb340b216ec33e53a3a629856afe1c6e0ef91d84a4e6f2fb2ca70fe", + "sha256:ba5b2e6fe6ca2b7e013398bc7d7b170e21cce322d266ffcd57cca313e54fb246", + "sha256:ba5c4a8552bff16c61882db58544116d021d0b31ee7c66958d14cf386a5b5350", + "sha256:c79e6a11a07da7374f46970410b41d5e266f7f38f6a17a9c4823db80dadf4303", + "sha256:ca48477862372ac3770969b9d75f1bf66131d386dba79506c46d75e6b48c1e09", + "sha256:dea7adcc33d5d105896401a1f37d56b47d443a2b2605ff8a969a0ed5543f7e33", + "sha256:e0a16d274b588767602b7646fa05af2782576a6cf1022f4ba74cbb4db66f6ca8", + "sha256:e4129b528c6baa99a429f97ce733fff478ec955513630e61b49804b6cf9b224a", + "sha256:e5f805d2d5d0a41633651a73fa4ecdd0b3d7a49de4ec3fadf062fe16501ddbf1", + "sha256:ef6c96b2baa2100ec91a4b428f80d8f28a3c9e53568219b6c298c1125572ebc6", + "sha256:fdbdd1d630195689f325c9ef1a12900524dceb503b00a987663ff4f58669b93d" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==1.10.12" + }, "pydocstyle": { "hashes": [ "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019", @@ -972,6 +1460,44 @@ ], "version": "==1.8.0" }, + "pyrsistent": { + "hashes": [ + "sha256:0724c506cd8b63c69c7f883cc233aac948c1ea946ea95996ad8b1380c25e1d3f", + "sha256:09848306523a3aba463c4b49493a760e7a6ca52e4826aa100ee99d8d39b7ad1e", + "sha256:0f3b1bcaa1f0629c978b355a7c37acd58907390149b7311b5db1b37648eb6958", + "sha256:21cc459636983764e692b9eba7144cdd54fdec23ccdb1e8ba392a63666c60c34", + "sha256:2e14c95c16211d166f59c6611533d0dacce2e25de0f76e4c140fde250997b3ca", + "sha256:2e2c116cc804d9b09ce9814d17df5edf1df0c624aba3b43bc1ad90411487036d", + "sha256:4021a7f963d88ccd15b523787d18ed5e5269ce57aa4037146a2377ff607ae87d", + "sha256:4c48f78f62ab596c679086084d0dd13254ae4f3d6c72a83ffdf5ebdef8f265a4", + "sha256:4f5c2d012671b7391803263419e31b5c7c21e7c95c8760d7fc35602353dee714", + "sha256:58b8f6366e152092194ae68fefe18b9f0b4f89227dfd86a07770c3d86097aebf", + "sha256:59a89bccd615551391f3237e00006a26bcf98a4d18623a19909a2c48b8e986ee", + "sha256:5cdd7ef1ea7a491ae70d826b6cc64868de09a1d5ff9ef8d574250d0940e275b8", + "sha256:6288b3fa6622ad8a91e6eb759cfc48ff3089e7c17fb1d4c59a919769314af224", + "sha256:6d270ec9dd33cdb13f4d62c95c1a5a50e6b7cdd86302b494217137f760495b9d", + "sha256:79ed12ba79935adaac1664fd7e0e585a22caa539dfc9b7c7c6d5ebf91fb89054", + "sha256:7d29c23bdf6e5438c755b941cef867ec2a4a172ceb9f50553b6ed70d50dfd656", + "sha256:8441cf9616d642c475684d6cf2520dd24812e996ba9af15e606df5f6fd9d04a7", + "sha256:881bbea27bbd32d37eb24dd320a5e745a2a5b092a17f6debc1349252fac85423", + "sha256:8c3aba3e01235221e5b229a6c05f585f344734bd1ad42a8ac51493d74722bbce", + "sha256:a14798c3005ec892bbada26485c2eea3b54109cb2533713e355c806891f63c5e", + "sha256:b14decb628fac50db5e02ee5a35a9c0772d20277824cfe845c8a8b717c15daa3", + "sha256:b318ca24db0f0518630e8b6f3831e9cba78f099ed5c1d65ffe3e023003043ba0", + "sha256:c1beb78af5423b879edaf23c5591ff292cf7c33979734c99aa66d5914ead880f", + "sha256:c55acc4733aad6560a7f5f818466631f07efc001fd023f34a6c203f8b6df0f0b", + "sha256:ca52d1ceae015859d16aded12584c59eb3825f7b50c6cfd621d4231a6cc624ce", + "sha256:cae40a9e3ce178415040a0383f00e8d68b569e97f31928a3a8ad37e3fde6df6a", + "sha256:e78d0c7c1e99a4a45c99143900ea0546025e41bb59ebc10182e947cf1ece9174", + "sha256:ef3992833fbd686ee783590639f4b8343a57f1f75de8633749d984dc0eb16c86", + "sha256:f058a615031eea4ef94ead6456f5ec2026c19fb5bd6bfe86e9665c4158cf802f", + "sha256:f5ac696f02b3fc01a710427585c855f65cd9c640e14f52abe52020722bb4906b", + "sha256:f920385a11207dc372a028b3f1e1038bb244b3ec38d448e6d8e43c6b3ba20e98", + "sha256:fed2c3216a605dc9a6ea50c7e84c82906e3684c4e80d2908208f662a6cbf9022" + ], + "markers": "python_version >= '3.8'", + "version": "==0.20.0" + }, "pytest": { "hashes": [ "sha256:130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e", @@ -983,12 +1509,12 @@ }, "pytest-asyncio": { "hashes": [ - "sha256:2143d9d9375bf372a73260e4114541485e84fca350b0b6b92674ca56ff5f7ea2", - "sha256:b0079dfac14b60cd1ce4691fbfb1748fe939db7d0234b5aba97197d10fbe0fef" + "sha256:68516fdd1018ac57b846c9846b954f0393b26f094764a28c955eabb0536a4e8a", + "sha256:ffe523a89c1c222598c76856e76852b787504ddb72dd5d9b6617ffa8aa2cde5f" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==0.23.4" + "version": "==0.23.6" }, "pytest-cov": { "hashes": [ @@ -1050,11 +1576,11 @@ }, "python-dateutil": { "hashes": [ - "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", - "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" + "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", + "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.8.2" + "version": "==2.9.0.post0" }, "pyyaml": { "hashes": [ @@ -1113,14 +1639,6 @@ "markers": "python_version >= '3.6'", "version": "==6.0.1" }, - "referencing": { - "hashes": [ - "sha256:39240f2ecc770258f28b642dd47fd74bc8b02484de54e1882b74b35ebd779bd5", - "sha256:c775fedf74bc0f9189c2a3be1c12fd03e8c23f4d371dce795df44e06c5b412f7" - ], - "markers": "python_version >= '3.8'", - "version": "==0.33.0" - }, "requests": { "hashes": [ "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61", @@ -1130,118 +1648,13 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", "version": "==2.27.1" }, - "rpds-py": { - "hashes": [ - "sha256:01f58a7306b64e0a4fe042047dd2b7d411ee82e54240284bab63e325762c1147", - "sha256:0210b2668f24c078307260bf88bdac9d6f1093635df5123789bfee4d8d7fc8e7", - "sha256:02866e060219514940342a1f84303a1ef7a1dad0ac311792fbbe19b521b489d2", - "sha256:0387ce69ba06e43df54e43968090f3626e231e4bc9150e4c3246947567695f68", - "sha256:060f412230d5f19fc8c8b75f315931b408d8ebf56aec33ef4168d1b9e54200b1", - "sha256:071bc28c589b86bc6351a339114fb7a029f5cddbaca34103aa573eba7b482382", - "sha256:0bfb09bf41fe7c51413f563373e5f537eaa653d7adc4830399d4e9bdc199959d", - "sha256:10162fe3f5f47c37ebf6d8ff5a2368508fe22007e3077bf25b9c7d803454d921", - "sha256:149c5cd24f729e3567b56e1795f74577aa3126c14c11e457bec1b1c90d212e38", - "sha256:1701fc54460ae2e5efc1dd6350eafd7a760f516df8dbe51d4a1c79d69472fbd4", - "sha256:1957a2ab607f9added64478a6982742eb29f109d89d065fa44e01691a20fc20a", - "sha256:1a746a6d49665058a5896000e8d9d2f1a6acba8a03b389c1e4c06e11e0b7f40d", - "sha256:1bfcad3109c1e5ba3cbe2f421614e70439f72897515a96c462ea657261b96518", - "sha256:1d36b2b59e8cc6e576f8f7b671e32f2ff43153f0ad6d0201250a7c07f25d570e", - "sha256:1db228102ab9d1ff4c64148c96320d0be7044fa28bd865a9ce628ce98da5973d", - "sha256:1dc29db3900cb1bb40353772417800f29c3d078dbc8024fd64655a04ee3c4bdf", - "sha256:1e626b365293a2142a62b9a614e1f8e331b28f3ca57b9f05ebbf4cf2a0f0bdc5", - "sha256:1f3c3461ebb4c4f1bbc70b15d20b565759f97a5aaf13af811fcefc892e9197ba", - "sha256:20de7b7179e2031a04042e85dc463a93a82bc177eeba5ddd13ff746325558aa6", - "sha256:24e4900a6643f87058a27320f81336d527ccfe503984528edde4bb660c8c8d59", - "sha256:2528ff96d09f12e638695f3a2e0c609c7b84c6df7c5ae9bfeb9252b6fa686253", - "sha256:25f071737dae674ca8937a73d0f43f5a52e92c2d178330b4c0bb6ab05586ffa6", - "sha256:270987bc22e7e5a962b1094953ae901395e8c1e1e83ad016c5cfcfff75a15a3f", - "sha256:292f7344a3301802e7c25c53792fae7d1593cb0e50964e7bcdcc5cf533d634e3", - "sha256:2953937f83820376b5979318840f3ee47477d94c17b940fe31d9458d79ae7eea", - "sha256:2a792b2e1d3038daa83fa474d559acfd6dc1e3650ee93b2662ddc17dbff20ad1", - "sha256:2a7b2f2f56a16a6d62e55354dd329d929560442bd92e87397b7a9586a32e3e76", - "sha256:2f4eb548daf4836e3b2c662033bfbfc551db58d30fd8fe660314f86bf8510b93", - "sha256:3664d126d3388a887db44c2e293f87d500c4184ec43d5d14d2d2babdb4c64cad", - "sha256:3677fcca7fb728c86a78660c7fb1b07b69b281964673f486ae72860e13f512ad", - "sha256:380e0df2e9d5d5d339803cfc6d183a5442ad7ab3c63c2a0982e8c824566c5ccc", - "sha256:3ac732390d529d8469b831949c78085b034bff67f584559340008d0f6041a049", - "sha256:4128980a14ed805e1b91a7ed551250282a8ddf8201a4e9f8f5b7e6225f54170d", - "sha256:4341bd7579611cf50e7b20bb8c2e23512a3dc79de987a1f411cb458ab670eb90", - "sha256:436474f17733c7dca0fbf096d36ae65277e8645039df12a0fa52445ca494729d", - "sha256:4dc889a9d8a34758d0fcc9ac86adb97bab3fb7f0c4d29794357eb147536483fd", - "sha256:4e21b76075c01d65d0f0f34302b5a7457d95721d5e0667aea65e5bb3ab415c25", - "sha256:516fb8c77805159e97a689e2f1c80655c7658f5af601c34ffdb916605598cda2", - "sha256:5576ee2f3a309d2bb403ec292d5958ce03953b0e57a11d224c1f134feaf8c40f", - "sha256:5a024fa96d541fd7edaa0e9d904601c6445e95a729a2900c5aec6555fe921ed6", - "sha256:5d0e8a6434a3fbf77d11448c9c25b2f25244226cfbec1a5159947cac5b8c5fa4", - "sha256:5e7d63ec01fe7c76c2dbb7e972fece45acbb8836e72682bde138e7e039906e2c", - "sha256:60e820ee1004327609b28db8307acc27f5f2e9a0b185b2064c5f23e815f248f8", - "sha256:637b802f3f069a64436d432117a7e58fab414b4e27a7e81049817ae94de45d8d", - "sha256:65dcf105c1943cba45d19207ef51b8bc46d232a381e94dd38719d52d3980015b", - "sha256:698ea95a60c8b16b58be9d854c9f993c639f5c214cf9ba782eca53a8789d6b19", - "sha256:70fcc6c2906cfa5c6a552ba7ae2ce64b6c32f437d8f3f8eea49925b278a61453", - "sha256:720215373a280f78a1814becb1312d4e4d1077b1202a56d2b0815e95ccb99ce9", - "sha256:7450dbd659fed6dd41d1a7d47ed767e893ba402af8ae664c157c255ec6067fde", - "sha256:7b7d9ca34542099b4e185b3c2a2b2eda2e318a7dbde0b0d83357a6d4421b5296", - "sha256:7fbd70cb8b54fe745301921b0816c08b6d917593429dfc437fd024b5ba713c58", - "sha256:81038ff87a4e04c22e1d81f947c6ac46f122e0c80460b9006e6517c4d842a6ec", - "sha256:810685321f4a304b2b55577c915bece4c4a06dfe38f6e62d9cc1d6ca8ee86b99", - "sha256:82ada4a8ed9e82e443fcef87e22a3eed3654dd3adf6e3b3a0deb70f03e86142a", - "sha256:841320e1841bb53fada91c9725e766bb25009cfd4144e92298db296fb6c894fb", - "sha256:8587fd64c2a91c33cdc39d0cebdaf30e79491cc029a37fcd458ba863f8815383", - "sha256:8ffe53e1d8ef2520ebcf0c9fec15bb721da59e8ef283b6ff3079613b1e30513d", - "sha256:9051e3d2af8f55b42061603e29e744724cb5f65b128a491446cc029b3e2ea896", - "sha256:91e5a8200e65aaac342a791272c564dffcf1281abd635d304d6c4e6b495f29dc", - "sha256:93432e747fb07fa567ad9cc7aaadd6e29710e515aabf939dfbed8046041346c6", - "sha256:938eab7323a736533f015e6069a7d53ef2dcc841e4e533b782c2bfb9fb12d84b", - "sha256:9584f8f52010295a4a417221861df9bea4c72d9632562b6e59b3c7b87a1522b7", - "sha256:9737bdaa0ad33d34c0efc718741abaafce62fadae72c8b251df9b0c823c63b22", - "sha256:99da0a4686ada4ed0f778120a0ea8d066de1a0a92ab0d13ae68492a437db78bf", - "sha256:99f567dae93e10be2daaa896e07513dd4bf9c2ecf0576e0533ac36ba3b1d5394", - "sha256:9bdf1303df671179eaf2cb41e8515a07fc78d9d00f111eadbe3e14262f59c3d0", - "sha256:9f0e4dc0f17dcea4ab9d13ac5c666b6b5337042b4d8f27e01b70fae41dd65c57", - "sha256:a000133a90eea274a6f28adc3084643263b1e7c1a5a66eb0a0a7a36aa757ed74", - "sha256:a3264e3e858de4fc601741498215835ff324ff2482fd4e4af61b46512dd7fc83", - "sha256:a71169d505af63bb4d20d23a8fbd4c6ce272e7bce6cc31f617152aa784436f29", - "sha256:a967dd6afda7715d911c25a6ba1517975acd8d1092b2f326718725461a3d33f9", - "sha256:aa5bfb13f1e89151ade0eb812f7b0d7a4d643406caaad65ce1cbabe0a66d695f", - "sha256:ae35e8e6801c5ab071b992cb2da958eee76340e6926ec693b5ff7d6381441745", - "sha256:b686f25377f9c006acbac63f61614416a6317133ab7fafe5de5f7dc8a06d42eb", - "sha256:b760a56e080a826c2e5af09002c1a037382ed21d03134eb6294812dda268c811", - "sha256:b86b21b348f7e5485fae740d845c65a880f5d1eda1e063bc59bef92d1f7d0c55", - "sha256:b9412abdf0ba70faa6e2ee6c0cc62a8defb772e78860cef419865917d86c7342", - "sha256:bd345a13ce06e94c753dab52f8e71e5252aec1e4f8022d24d56decd31e1b9b23", - "sha256:be22ae34d68544df293152b7e50895ba70d2a833ad9566932d750d3625918b82", - "sha256:bf046179d011e6114daf12a534d874958b039342b347348a78b7cdf0dd9d6041", - "sha256:c3d2010656999b63e628a3c694f23020322b4178c450dc478558a2b6ef3cb9bb", - "sha256:c64602e8be701c6cfe42064b71c84ce62ce66ddc6422c15463fd8127db3d8066", - "sha256:d65e6b4f1443048eb7e833c2accb4fa7ee67cc7d54f31b4f0555b474758bee55", - "sha256:d8bbd8e56f3ba25a7d0cf980fc42b34028848a53a0e36c9918550e0280b9d0b6", - "sha256:da1ead63368c04a9bded7904757dfcae01eba0e0f9bc41d3d7f57ebf1c04015a", - "sha256:dbbb95e6fc91ea3102505d111b327004d1c4ce98d56a4a02e82cd451f9f57140", - "sha256:dbc56680ecf585a384fbd93cd42bc82668b77cb525343170a2d86dafaed2a84b", - "sha256:df3b6f45ba4515632c5064e35ca7f31d51d13d1479673185ba8f9fefbbed58b9", - "sha256:dfe07308b311a8293a0d5ef4e61411c5c20f682db6b5e73de6c7c8824272c256", - "sha256:e796051f2070f47230c745d0a77a91088fbee2cc0502e9b796b9c6471983718c", - "sha256:efa767c220d94aa4ac3a6dd3aeb986e9f229eaf5bce92d8b1b3018d06bed3772", - "sha256:f0b8bf5b8db49d8fd40f54772a1dcf262e8be0ad2ab0206b5a2ec109c176c0a4", - "sha256:f175e95a197f6a4059b50757a3dca33b32b61691bdbd22c29e8a8d21d3914cae", - "sha256:f2f3b28b40fddcb6c1f1f6c88c6f3769cd933fa493ceb79da45968a21dccc920", - "sha256:f6c43b6f97209e370124baf2bf40bb1e8edc25311a158867eb1c3a5d449ebc7a", - "sha256:f7f4cb1f173385e8a39c29510dd11a78bf44e360fb75610594973f5ea141028b", - "sha256:fad059a4bd14c45776600d223ec194e77db6c20255578bb5bcdd7c18fd169361", - "sha256:ff1dcb8e8bc2261a088821b2595ef031c91d499a0c1b031c152d43fe0a6ecec8", - "sha256:ffee088ea9b593cc6160518ba9bd319b5475e5f3e578e4552d63818773c6f56a" - ], - "markers": "python_version >= '3.8'", - "version": "==0.17.1" - }, "ruamel.yaml": { "hashes": [ - "sha256:61917e3a35a569c1133a8f772e1226961bf5a1198bea7e23f06a0841dea1ab0e", - "sha256:a013ac02f99a69cdd6277d9664689eb1acba07069f912823177c5eced21a6ada" + "sha256:57b53ba33def16c4f3d807c0ccbc00f8a6081827e81ba2491691b76882d0c636", + "sha256:8b27e6a217e786c6fbe5634d8f3f11bc63e0f80f6a5890f28863d9c45aac311b" ], "markers": "python_version >= '3.7'", - "version": "==0.18.5" + "version": "==0.18.6" }, "ruamel.yaml.clib": { "hashes": [ @@ -1309,11 +1722,11 @@ }, "sniffio": { "hashes": [ - "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101", - "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384" + "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", + "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" ], "markers": "python_version >= '3.7'", - "version": "==1.3.0" + "version": "==1.3.1" }, "snowballstemmer": { "hashes": [ @@ -1358,12 +1771,12 @@ }, "types-mock": { "hashes": [ - "sha256:13ca379d5710ccb3f18f69ade5b08881874cb83383d8fb49b1d4dac9d5c5d090", - "sha256:3d116955495935b0bcba14954b38d97e507cd43eca3e3700fc1b8e4f5c6bf2c7" + "sha256:0769cb376dfc75b45215619f17a9fd6333d771cc29ce4a38937f060b1e45530f", + "sha256:7472797986d83016f96fde7f73577d129b0cd8a8d0b783487a7be330d57ba431" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==5.1.0.20240106" + "version": "==5.1.0.20240311" }, "types-paho-mqtt": { "hashes": [ @@ -1391,12 +1804,12 @@ }, "typing-extensions": { "hashes": [ - "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", - "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0", + "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.9.0" + "version": "==4.11.0" }, "urllib3": { "hashes": [ diff --git a/robot-server/robot_server/deck_configuration/defaults.py b/robot-server/robot_server/deck_configuration/defaults.py index a591e9798df..3ed9a5ed395 100644 --- a/robot-server/robot_server/deck_configuration/defaults.py +++ b/robot-server/robot_server/deck_configuration/defaults.py @@ -7,40 +7,64 @@ _for_flex = models.DeckConfigurationRequest.construct( cutoutFixtures=[ models.CutoutFixture.construct( - cutoutId="cutoutA1", cutoutFixtureId="singleLeftSlot" + cutoutId="cutoutA1", + cutoutFixtureId="singleLeftSlot", + opentronsModuleSerialNumber=None, ), models.CutoutFixture.construct( - cutoutId="cutoutB1", cutoutFixtureId="singleLeftSlot" + cutoutId="cutoutB1", + cutoutFixtureId="singleLeftSlot", + opentronsModuleSerialNumber=None, ), models.CutoutFixture.construct( - cutoutId="cutoutC1", cutoutFixtureId="singleLeftSlot" + cutoutId="cutoutC1", + cutoutFixtureId="singleLeftSlot", + opentronsModuleSerialNumber=None, ), models.CutoutFixture.construct( - cutoutId="cutoutD1", cutoutFixtureId="singleLeftSlot" + cutoutId="cutoutD1", + cutoutFixtureId="singleLeftSlot", + opentronsModuleSerialNumber=None, ), models.CutoutFixture.construct( - cutoutId="cutoutA2", cutoutFixtureId="singleCenterSlot" + cutoutId="cutoutA2", + cutoutFixtureId="singleCenterSlot", + opentronsModuleSerialNumber=None, ), models.CutoutFixture.construct( - cutoutId="cutoutB2", cutoutFixtureId="singleCenterSlot" + cutoutId="cutoutB2", + cutoutFixtureId="singleCenterSlot", + opentronsModuleSerialNumber=None, ), models.CutoutFixture.construct( - cutoutId="cutoutC2", cutoutFixtureId="singleCenterSlot" + cutoutId="cutoutC2", + cutoutFixtureId="singleCenterSlot", + opentronsModuleSerialNumber=None, ), models.CutoutFixture.construct( - cutoutId="cutoutD2", cutoutFixtureId="singleCenterSlot" + cutoutId="cutoutD2", + cutoutFixtureId="singleCenterSlot", + opentronsModuleSerialNumber=None, ), models.CutoutFixture.construct( - cutoutId="cutoutA3", cutoutFixtureId="trashBinAdapter" + cutoutId="cutoutA3", + cutoutFixtureId="trashBinAdapter", + opentronsModuleSerialNumber=None, ), models.CutoutFixture.construct( - cutoutId="cutoutB3", cutoutFixtureId="singleRightSlot" + cutoutId="cutoutB3", + cutoutFixtureId="singleRightSlot", + opentronsModuleSerialNumber=None, ), models.CutoutFixture.construct( - cutoutId="cutoutC3", cutoutFixtureId="singleRightSlot" + cutoutId="cutoutC3", + cutoutFixtureId="singleRightSlot", + opentronsModuleSerialNumber=None, ), models.CutoutFixture.construct( - cutoutId="cutoutD3", cutoutFixtureId="singleRightSlot" + cutoutId="cutoutD3", + cutoutFixtureId="singleRightSlot", + opentronsModuleSerialNumber=None, ), ] ) @@ -49,40 +73,64 @@ _for_ot2 = models.DeckConfigurationRequest.construct( cutoutFixtures=[ models.CutoutFixture.construct( - cutoutId="cutout1", cutoutFixtureId="singleStandardSlot" + cutoutId="cutout1", + cutoutFixtureId="singleStandardSlot", + opentronsModuleSerialNumber=None, ), models.CutoutFixture.construct( - cutoutId="cutout2", cutoutFixtureId="singleStandardSlot" + cutoutId="cutout2", + cutoutFixtureId="singleStandardSlot", + opentronsModuleSerialNumber=None, ), models.CutoutFixture.construct( - cutoutId="cutout3", cutoutFixtureId="singleStandardSlot" + cutoutId="cutout3", + cutoutFixtureId="singleStandardSlot", + opentronsModuleSerialNumber=None, ), models.CutoutFixture.construct( - cutoutId="cutout4", cutoutFixtureId="singleStandardSlot" + cutoutId="cutout4", + cutoutFixtureId="singleStandardSlot", + opentronsModuleSerialNumber=None, ), models.CutoutFixture.construct( - cutoutId="cutout5", cutoutFixtureId="singleStandardSlot" + cutoutId="cutout5", + cutoutFixtureId="singleStandardSlot", + opentronsModuleSerialNumber=None, ), models.CutoutFixture.construct( - cutoutId="cutout6", cutoutFixtureId="singleStandardSlot" + cutoutId="cutout6", + cutoutFixtureId="singleStandardSlot", + opentronsModuleSerialNumber=None, ), models.CutoutFixture.construct( - cutoutId="cutout7", cutoutFixtureId="singleStandardSlot" + cutoutId="cutout7", + cutoutFixtureId="singleStandardSlot", + opentronsModuleSerialNumber=None, ), models.CutoutFixture.construct( - cutoutId="cutout8", cutoutFixtureId="singleStandardSlot" + cutoutId="cutout8", + cutoutFixtureId="singleStandardSlot", + opentronsModuleSerialNumber=None, ), models.CutoutFixture.construct( - cutoutId="cutout9", cutoutFixtureId="singleStandardSlot" + cutoutId="cutout9", + cutoutFixtureId="singleStandardSlot", + opentronsModuleSerialNumber=None, ), models.CutoutFixture.construct( - cutoutId="cutout10", cutoutFixtureId="singleStandardSlot" + cutoutId="cutout10", + cutoutFixtureId="singleStandardSlot", + opentronsModuleSerialNumber=None, ), models.CutoutFixture.construct( - cutoutId="cutout11", cutoutFixtureId="singleStandardSlot" + cutoutId="cutout11", + cutoutFixtureId="singleStandardSlot", + opentronsModuleSerialNumber=None, ), models.CutoutFixture.construct( - cutoutId="cutout12", cutoutFixtureId="fixedTrashSlot" + cutoutId="cutout12", + cutoutFixtureId="fixedTrashSlot", + opentronsModuleSerialNumber=None, ), ] ) diff --git a/robot-server/robot_server/deck_configuration/fastapi_dependencies.py b/robot-server/robot_server/deck_configuration/fastapi_dependencies.py index 699c0ce2e6d..f2cae3ab468 100644 --- a/robot-server/robot_server/deck_configuration/fastapi_dependencies.py +++ b/robot-server/robot_server/deck_configuration/fastapi_dependencies.py @@ -19,6 +19,10 @@ get_active_persistence_directory, get_active_persistence_directory_failsafe, ) +from robot_server.service.notifications import ( + DeckConfigurationPublisher, + get_deck_configuration_publisher, +) # This needs to be kept in sync with opentrons.execute, which reads this file. @@ -32,6 +36,9 @@ async def get_deck_configuration_store( app_state: AppState = fastapi.Depends(get_app_state), deck_type: DeckType = fastapi.Depends(get_deck_type), persistence_directory: Path = fastapi.Depends(get_active_persistence_directory), + deck_configuration_publisher: DeckConfigurationPublisher = fastapi.Depends( + get_deck_configuration_publisher + ), ) -> DeckConfigurationStore: """Return the server's singleton `DeckConfigurationStore`.""" deck_configuration_store = _accessor.get_from(app_state) @@ -39,7 +46,11 @@ async def get_deck_configuration_store( path = persistence_directory / _DECK_CONFIGURATION_FILE_NAME # If this initialization becomes async, we will need to protect it with a lock, # to protect against the bug described in https://github.com/Opentrons/opentrons/pull/11927. - deck_configuration_store = DeckConfigurationStore(deck_type, path) + deck_configuration_store = DeckConfigurationStore( + deck_type=deck_type, + path=path, + deck_configuration_publisher=deck_configuration_publisher, + ) _accessor.set_on(app_state, deck_configuration_store) return deck_configuration_store @@ -51,6 +62,9 @@ async def get_deck_configuration_store_failsafe( persistence_directory: Optional[Path] = fastapi.Depends( get_active_persistence_directory_failsafe ), + deck_configuration_publisher: DeckConfigurationPublisher = fastapi.Depends( + get_deck_configuration_publisher + ), ) -> Optional[DeckConfigurationStore]: """Return the server's singleton `DeckConfigurationStore`. @@ -66,6 +80,10 @@ async def get_deck_configuration_store_failsafe( path = persistence_directory / _DECK_CONFIGURATION_FILE_NAME # If this initialization becomes async, we will need to protect it with a lock, # to protect against the bug described in https://github.com/Opentrons/opentrons/pull/11927. - deck_configuration_store = DeckConfigurationStore(deck_type, path) + deck_configuration_store = DeckConfigurationStore( + deck_type=deck_type, + path=path, + deck_configuration_publisher=deck_configuration_publisher, + ) _accessor.set_on(app_state, deck_configuration_store) return deck_configuration_store diff --git a/robot-server/robot_server/deck_configuration/models.py b/robot-server/robot_server/deck_configuration/models.py index f0d2a7cd6bd..b84b395a667 100644 --- a/robot-server/robot_server/deck_configuration/models.py +++ b/robot-server/robot_server/deck_configuration/models.py @@ -33,6 +33,13 @@ class CutoutFixture(pydantic.BaseModel): " [deck definition](https://github.com/Opentrons/opentrons/tree/edge/shared-data/deck)." ) ) + opentronsModuleSerialNumber: Optional[str] = pydantic.Field( + description=( + "The serial number of a module loaded as a fixture." + " [deck definition](https://github.com/Opentrons/opentrons/tree/edge/shared-data/deck)." + ), + default=None, + ) class DeckConfigurationRequest(pydantic.BaseModel): diff --git a/robot-server/robot_server/deck_configuration/router.py b/robot-server/robot_server/deck_configuration/router.py index 4e00a3d707e..6e9d68d9f1b 100644 --- a/robot-server/robot_server/deck_configuration/router.py +++ b/robot-server/robot_server/deck_configuration/router.py @@ -7,7 +7,7 @@ import fastapi from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY -from opentrons_shared_data.deck.dev_types import DeckDefinitionV4 +from opentrons_shared_data.deck.dev_types import DeckDefinitionV5 from robot_server.errors.error_responses import ErrorBody from robot_server.hardware import get_deck_definition @@ -64,7 +64,7 @@ async def put_deck_configuration( # noqa: D103 request_body: RequestModel[models.DeckConfigurationRequest], store: DeckConfigurationStore = fastapi.Depends(get_deck_configuration_store), now: datetime = fastapi.Depends(get_current_time), - deck_definition: DeckDefinitionV4 = fastapi.Depends(get_deck_definition), + deck_definition: DeckDefinitionV5 = fastapi.Depends(get_deck_definition), ) -> PydanticResponse[ Union[ SimpleBody[models.DeckConfigurationResponse], diff --git a/robot-server/robot_server/deck_configuration/store.py b/robot-server/robot_server/deck_configuration/store.py index feffa539ec0..9cf869ce4a8 100644 --- a/robot-server/robot_server/deck_configuration/store.py +++ b/robot-server/robot_server/deck_configuration/store.py @@ -15,6 +15,8 @@ from opentrons.protocol_engine.types import DeckType +from robot_server.service.notifications import DeckConfigurationPublisher + from . import defaults from . import models from opentrons.protocol_engine.types import DeckConfigurationType @@ -22,7 +24,12 @@ # TODO(mm, 2023-11-17): Add unit tests for DeckConfigurationStore. class DeckConfigurationStore: # noqa: D101 - def __init__(self, deck_type: DeckType, path: Path) -> None: + def __init__( + self, + deck_type: DeckType, + path: Path, + deck_configuration_publisher: DeckConfigurationPublisher, + ) -> None: """A persistent store of the robot's deck configuration. Params: @@ -37,6 +44,7 @@ def __init__(self, deck_type: DeckType, path: Path) -> None: self._deck_type = deck_type self._path = anyio.Path(path) + self._deck_configuration_publisher = deck_configuration_publisher # opentrons.calibration_storage is not generally safe for concurrent access. self._lock = asyncio.Lock() @@ -54,12 +62,16 @@ async def set( path=self._path, cutout_fixture_placements=[ calibration_storage_types.CutoutFixturePlacement( - cutout_fixture_id=e.cutoutFixtureId, cutout_id=e.cutoutId + cutout_fixture_id=e.cutoutFixtureId, + cutout_id=e.cutoutId, + opentrons_module_serial_number=e.opentronsModuleSerialNumber, ) for e in request.cutoutFixtures ], last_modified_at=last_modified_at, ) + await self._deck_configuration_publisher.publish_deck_configuration() + return await self._get_assuming_locked() async def get(self) -> models.DeckConfigurationResponse: @@ -71,7 +83,8 @@ async def get_deck_configuration(self) -> DeckConfigurationType: """Get the robot's current deck configuration in an expected typing.""" to_convert = await self.get() converted = [ - (item.cutoutId, item.cutoutFixtureId) for item in to_convert.cutoutFixtures + (item.cutoutId, item.cutoutFixtureId, item.opentronsModuleSerialNumber) + for item in to_convert.cutoutFixtures ] return converted @@ -79,6 +92,7 @@ async def delete(self) -> None: """Delete the robot's current deck configuration, resetting it to the default.""" async with self._lock: await self._path.unlink(missing_ok=True) + await self._deck_configuration_publisher.publish_deck_configuration() async def _get_assuming_locked(self) -> models.DeckConfigurationResponse: from_storage = await _read(self._path) @@ -102,6 +116,7 @@ async def _get_assuming_locked(self) -> models.DeckConfigurationResponse: models.CutoutFixture.construct( cutoutFixtureId=e.cutout_fixture_id, cutoutId=e.cutout_id, + opentronsModuleSerialNumber=e.opentrons_module_serial_number, ) for e in cutout_fixtures_from_storage ] diff --git a/robot-server/robot_server/deck_configuration/validation.py b/robot-server/robot_server/deck_configuration/validation.py index 0530a4f9271..a3c043f8f51 100644 --- a/robot-server/robot_server/deck_configuration/validation.py +++ b/robot-server/robot_server/deck_configuration/validation.py @@ -3,7 +3,7 @@ from collections import defaultdict from dataclasses import dataclass -from typing import DefaultDict, FrozenSet, List, Set, Tuple, Union +from typing import DefaultDict, FrozenSet, List, Set, Tuple, Union, Optional from opentrons_shared_data.deck import dev_types as deck_types @@ -14,6 +14,7 @@ class Placement: cutout_id: str cutout_fixture_id: str + opentrons_module_serial_number: Optional[str] @dataclass(frozen=True) @@ -43,22 +44,51 @@ class InvalidLocationError: @dataclass(frozen=True) class UnrecognizedCutoutFixtureError: - """When an cutout fixture has been mounted that's not defined by the deck definition.""" + """When a cutout fixture has been mounted that's not defined by the deck definition.""" cutout_fixture_id: str allowed_cutout_fixture_ids: FrozenSet[str] +@dataclass(frozen=True) +class InvalidSerialNumberError: + """When a module cutout fixture has been mounted but not given a serial number.""" + + cutout_id: str + cutout_fixture_id: str + + +@dataclass(frozen=True) +class UnexpectedSerialNumberError: + """When a cutout fixture that is not a module has been provided a serial number.""" + + cutout_id: str + cutout_fixture_id: str + opentrons_module_serial_number: str + + +@dataclass(frozen=True) +class MissingGroupFixtureError: + """When a member of a fixture group has been mounted but other required members of that group have not.""" + + cutout_id: str + cutout_fixture_id: str + missing_fixture_id: str + + ConfigurationError = Union[ UnoccupiedCutoutError, OvercrowdedCutoutError, InvalidLocationError, UnrecognizedCutoutFixtureError, + InvalidSerialNumberError, + UnexpectedSerialNumberError, + MissingGroupFixtureError, ] -def get_configuration_errors( - deck_definition: deck_types.DeckDefinitionV4, +def get_configuration_errors( # noqa: C901 + deck_definition: deck_types.DeckDefinitionV5, placements: List[Placement], ) -> Set[ConfigurationError]: """Return all the problems with the given deck configration. @@ -98,12 +128,55 @@ def get_configuration_errors( allowed_cutout_ids=allowed_cutout_ids, ) ) + if found_cutout_fixture[ + "expectOpentronsModuleSerialNumber" + ] is False and isinstance(placement.opentrons_module_serial_number, str): + errors.add( + UnexpectedSerialNumberError( + cutout_id=placement.cutout_id, + cutout_fixture_id=placement.cutout_fixture_id, + opentrons_module_serial_number=placement.opentrons_module_serial_number, + ) + ) + elif ( + found_cutout_fixture["expectOpentronsModuleSerialNumber"] is True + and placement.opentrons_module_serial_number is None + ): + errors.add( + InvalidSerialNumberError( + cutout_id=placement.cutout_id, + cutout_fixture_id=placement.cutout_fixture_id, + ) + ) + for cutout_id in found_cutout_fixture["fixtureGroup"]: + if cutout_id == placement.cutout_id: + map = found_cutout_fixture["fixtureGroup"][cutout_id] + member_found = False + for item in map: + for group_member_cutout_id in item: + group_member_fixture_id = item[group_member_cutout_id] + for deck_item in placements: + if ( + group_member_fixture_id + == deck_item.cutout_fixture_id + and group_member_cutout_id == deck_item.cutout_id + ): + member_found = True + if member_found is False: + errors.add( + MissingGroupFixtureError( + cutout_id=placement.cutout_id, + cutout_fixture_id=placement.cutout_fixture_id, + missing_fixture_id=group_member_fixture_id, + ) + ) + member_found = False return errors def _find_cutout_fixture( - deck_definition: deck_types.DeckDefinitionV4, cutout_fixture_id: str + deck_definition: deck_types.DeckDefinitionV5, cutout_fixture_id: str ) -> Union[deck_types.CutoutFixture, UnrecognizedCutoutFixtureError]: cutout_fixtures = deck_definition["cutoutFixtures"] try: diff --git a/robot-server/robot_server/deck_configuration/validation_mapping.py b/robot-server/robot_server/deck_configuration/validation_mapping.py index 10d9b65158a..1337218075c 100644 --- a/robot-server/robot_server/deck_configuration/validation_mapping.py +++ b/robot-server/robot_server/deck_configuration/validation_mapping.py @@ -10,7 +10,11 @@ def map_in(request: models.DeckConfigurationRequest) -> List[validation.Placement]: """Map a request from HTTP to internal types that can be validated.""" return [ - validation.Placement(cutout_id=p.cutoutId, cutout_fixture_id=p.cutoutFixtureId) + validation.Placement( + cutout_id=p.cutoutId, + cutout_fixture_id=p.cutoutFixtureId, + opentrons_module_serial_number=p.opentronsModuleSerialNumber, + ) for p in request.cutoutFixtures ] diff --git a/robot-server/robot_server/hardware.py b/robot-server/robot_server/hardware.py index c72a162b1be..2994248a302 100644 --- a/robot-server/robot_server/hardware.py +++ b/robot-server/robot_server/hardware.py @@ -381,9 +381,9 @@ async def get_deck_type() -> DeckType: async def get_deck_definition( deck_type: DeckType = Depends(get_deck_type), -) -> deck.dev_types.DeckDefinitionV4: +) -> deck.dev_types.DeckDefinitionV5: """Return this robot's deck definition.""" - return deck.load(deck_type, version=4) + return deck.load(deck_type, version=5) async def _postinit_ot2_tasks( diff --git a/robot-server/robot_server/maintenance_runs/maintenance_action_models.py b/robot-server/robot_server/maintenance_runs/maintenance_action_models.py deleted file mode 100644 index 1eb34809dd5..00000000000 --- a/robot-server/robot_server/maintenance_runs/maintenance_action_models.py +++ /dev/null @@ -1,44 +0,0 @@ -"""Request and response models for controlling maintenance runs with actions.""" -from datetime import datetime -from enum import Enum -from pydantic import BaseModel, Field - -from robot_server.service.json_api import ResourceModel - - -class MaintenanceRunActionType(str, Enum): - """Types of run control actions. - - Args: - PLAY: Start or resume a protocol run. - PAUSE: Pause a run. - STOP: Stop (cancel) a run. - """ - - PLAY = "play" - PAUSE = "pause" - STOP = "stop" - - -class MaintenanceRunActionCreate(BaseModel): - """Request model for new control action creation.""" - - actionType: MaintenanceRunActionType - - -class MaintenanceRunAction(ResourceModel): - """Maintenance Run control action model. - - A MaintenanceRunAction resource represents a client-provided command to - the run in order to control the execution of the run itself. - - This is different than a run command, which represents an individual - robotic procedure to be executed. - """ - - id: str = Field(..., description="A unique identifier to reference the command.") - createdAt: datetime = Field(..., description="When the command was created.") - actionType: MaintenanceRunActionType = Field( - ..., - description="Specific type of action, which determines behavior.", - ) diff --git a/robot-server/robot_server/maintenance_runs/maintenance_engine_store.py b/robot-server/robot_server/maintenance_runs/maintenance_engine_store.py index 3b60f38f533..c70d2a1dd07 100644 --- a/robot-server/robot_server/maintenance_runs/maintenance_engine_store.py +++ b/robot-server/robot_server/maintenance_runs/maintenance_engine_store.py @@ -1,7 +1,10 @@ """In-memory storage of ProtocolEngine instances.""" +import asyncio +import logging from datetime import datetime from typing import List, NamedTuple, Optional, Callable +from opentrons.protocol_engine.errors.exceptions import EStopActivatedError from opentrons.protocol_engine.types import PostRunHardwareState from opentrons_shared_data.robot.dev_types import RobotType from opentrons_shared_data.robot.dev_types import RobotTypeEnum @@ -27,6 +30,9 @@ from opentrons.protocol_engine.types import DeckConfigurationType +_log = logging.getLogger(__name__) + + class EngineConflictError(RuntimeError): """An error raised if an active engine is already initialized. @@ -48,18 +54,47 @@ class RunnerEnginePair(NamedTuple): engine: ProtocolEngine -def get_estop_listener(engine_store: "MaintenanceEngineStore") -> HardwareEventHandler: - """Create a callback for estop events.""" +async def handle_estop_event( + engine_store: "MaintenanceEngineStore", event: HardwareEvent +) -> None: + """Handle an E-stop event from the hardware API. - def _callback(event: HardwareEvent) -> None: + This is meant to run in the engine's thread and asyncio event loop. + + This is a public function for unit-testing purposes, but it's an implementation + detail of the store. + """ + try: if isinstance(event, EstopStateNotification): if event.new_state is not EstopState.PHYSICALLY_ENGAGED: return if engine_store.current_run_id is None: return - engine_store.engine.estop(maintenance_run=True) + # todo(mm, 2024-04-17): This estop teardown sequencing belongs in the + # runner layer. + engine_store.engine.estop() + await engine_store.engine.finish(error=EStopActivatedError()) + except Exception: + # This is a background task kicked off by a hardware event, + # so there's no one to propagate this exception to. + _log.exception("Exception handling E-stop event.") + + +def _get_estop_listener(engine_store: "MaintenanceEngineStore") -> HardwareEventHandler: + """Create a callback for estop events. + + The returned callback is meant to run in the hardware API's thread. + """ + engine_loop = asyncio.get_running_loop() - return _callback + def run_handler_in_engine_thread_from_hardware_thread( + event: HardwareEvent, + ) -> None: + asyncio.run_coroutine_threadsafe( + handle_estop_event(engine_store, event), engine_loop + ) + + return run_handler_in_engine_thread_from_hardware_thread class MaintenanceEngineStore: @@ -83,15 +118,7 @@ def __init__( self._robot_type = robot_type self._deck_type = deck_type self._runner_engine_pair: Optional[RunnerEnginePair] = None - hardware_api.register_callback(get_estop_listener(self)) - - def _estop_listener(self, event: HardwareEvent) -> None: - if isinstance(event, EstopStateNotification): - if event.new_state is not EstopState.PHYSICALLY_ENGAGED: - return - if self._runner_engine_pair is None: - return - self._runner_engine_pair.engine.estop(maintenance_run=True) + hardware_api.register_callback(_get_estop_listener(self)) @property def engine(self) -> ProtocolEngine: diff --git a/robot-server/robot_server/maintenance_runs/maintenance_run_models.py b/robot-server/robot_server/maintenance_runs/maintenance_run_models.py index f4d1a19dc61..00379034d9b 100644 --- a/robot-server/robot_server/maintenance_runs/maintenance_run_models.py +++ b/robot-server/robot_server/maintenance_runs/maintenance_run_models.py @@ -17,7 +17,6 @@ LabwareOffsetCreate, Liquid, ) -from robot_server.maintenance_runs.maintenance_action_models import MaintenanceRunAction from robot_server.service.json_api import ResourceModel @@ -70,9 +69,15 @@ class MaintenanceRun(ResourceModel): " There can be, at most, one current run." ), ) - actions: List[MaintenanceRunAction] = Field( + actions: List[object] = Field( ..., - description="Client-initiated run control actions.", + description=( + " This is currently always an empty list," + " and is provided for symmetry with non-maintenance runs." + " Non-maintenance runs let you issue actions with" + " `POST /runs/{id}/actions`, but there is currently no equivalent" + " endpoint for maintenance runs." + ), ) errors: List[ErrorOccurrence] = Field( ..., diff --git a/robot-server/robot_server/maintenance_runs/router/base_router.py b/robot-server/robot_server/maintenance_runs/router/base_router.py index c115d46509f..54533d8f977 100644 --- a/robot-server/robot_server/maintenance_runs/router/base_router.py +++ b/robot-server/robot_server/maintenance_runs/router/base_router.py @@ -39,7 +39,7 @@ get_deck_configuration_store, ) from robot_server.deck_configuration.store import DeckConfigurationStore -from robot_server.service.notifications import get_notify_publishers +from robot_server.service.notifications import get_pe_notify_publishers log = logging.getLogger(__name__) base_router = APIRouter() @@ -156,7 +156,7 @@ async def create_run( deck_configuration_store: DeckConfigurationStore = Depends( get_deck_configuration_store ), - notify_publishers: Callable[[], None] = Depends(get_notify_publishers), + notify_publishers: Callable[[], None] = Depends(get_pe_notify_publishers), ) -> PydanticResponse[SimpleBody[MaintenanceRun]]: """Create a new maintenance run. diff --git a/robot-server/robot_server/persistence/_migrations/v3_to_v4.py b/robot-server/robot_server/persistence/_migrations/v3_to_v4.py index 8b4445aaec3..b67d11d34ec 100644 --- a/robot-server/robot_server/persistence/_migrations/v3_to_v4.py +++ b/robot-server/robot_server/persistence/_migrations/v3_to_v4.py @@ -3,6 +3,7 @@ Summary of changes from schema 3: - Adds a new "run_time_parameter_values_and_defaults" column to analysis table +- Adds a new "run_time_parameters" column to run table """ from pathlib import Path @@ -50,3 +51,8 @@ def add_column( schema_4.analysis_table.name, schema_4.analysis_table.c.run_time_parameter_values_and_defaults, ) + add_column( + dest_engine, + schema_4.run_table.name, + schema_4.run_table.c.run_time_parameters, + ) diff --git a/robot-server/robot_server/persistence/pydantic.py b/robot-server/robot_server/persistence/pydantic.py index c3486394ad4..c56312ec166 100644 --- a/robot-server/robot_server/persistence/pydantic.py +++ b/robot-server/robot_server/persistence/pydantic.py @@ -1,7 +1,8 @@ """Store Pydantic objects in the SQL database.""" -from typing import Type, TypeVar -from pydantic import BaseModel, parse_raw_as +import json +from typing import Type, TypeVar, List, Sequence +from pydantic import BaseModel, parse_raw_as, parse_obj_as _BaseModelT = TypeVar("_BaseModelT", bound=BaseModel) @@ -17,6 +18,16 @@ def pydantic_to_json(obj: BaseModel) -> str: ) -def json_to_pydantic(model: Type[_BaseModelT], json: str) -> _BaseModelT: +def pydantic_list_to_json(obj_list: Sequence[BaseModel]) -> str: + """Serialize a list of Pydantic objects for storing in the SQL database.""" + return json.dumps([obj.dict(by_alias=True, exclude_none=True) for obj in obj_list]) + + +def json_to_pydantic(model: Type[_BaseModelT], json_str: str) -> _BaseModelT: """Parse a Pydantic object stored in the SQL database.""" - return parse_raw_as(model, json) + return parse_raw_as(model, json_str) + + +def json_to_pydantic_list(model: Type[_BaseModelT], json_str: str) -> List[_BaseModelT]: + """Parse a list of Pydantic objects stored in the SQL database.""" + return [parse_obj_as(model, obj_dict) for obj_dict in json.loads(json_str)] diff --git a/robot-server/robot_server/persistence/tables/schema_4.py b/robot-server/robot_server/persistence/tables/schema_4.py index 47d29d3d8f3..d1662bf7adc 100644 --- a/robot-server/robot_server/persistence/tables/schema_4.py +++ b/robot-server/robot_server/persistence/tables/schema_4.py @@ -85,6 +85,13 @@ sqlalchemy.Column("engine_status", sqlalchemy.String, nullable=True), # column added in schema v1 sqlalchemy.Column("_updated_at", UTCDateTime, nullable=True), + # column added in schema v4 + sqlalchemy.Column( + "run_time_parameters", + # Stores a JSON string. See RunStore. + sqlalchemy.String, + nullable=True, + ), ) action_table = sqlalchemy.Table( diff --git a/robot-server/robot_server/protocols/analysis_memcache.py b/robot-server/robot_server/protocols/analysis_memcache.py index 19280009bd5..3ba3156607f 100644 --- a/robot-server/robot_server/protocols/analysis_memcache.py +++ b/robot-server/robot_server/protocols/analysis_memcache.py @@ -63,3 +63,14 @@ def insert(self, key: K, value: V) -> None: self._pop_eldest(key) self._cache[key] = value self._cache_order.appendleft(key) + + def remove(self, key: K) -> None: + """Remove the cached element specified by the key. + + If no such element exists in cache, then simply no-op. + """ + try: + self._cache.pop(key) + self._cache_order.remove(key) # O(n) operation, use sparingly + except KeyError: + pass diff --git a/robot-server/robot_server/protocols/analysis_store.py b/robot-server/robot_server/protocols/analysis_store.py index b0ea474ec07..4f5b66ed4f8 100644 --- a/robot-server/robot_server/protocols/analysis_store.py +++ b/robot-server/robot_server/protocols/analysis_store.py @@ -129,8 +129,6 @@ def add_pending(self, protocol_id: str, analysis_id: str) -> AnalysisSummary: Returns: A summary of the just-added analysis. """ - # TODO (spp, 2024-03-19): cap the number of analyses being stored by - # auto-deleting old ones new_pending_analysis = self._pending_store.add( protocol_id=protocol_id, analysis_id=analysis_id ) @@ -198,7 +196,7 @@ async def update( completed_analysis ), ) - await self._completed_store.add( + await self._completed_store.make_room_and_add( completed_analysis_resource=completed_analysis_resource ) diff --git a/robot-server/robot_server/protocols/completed_analysis_store.py b/robot-server/robot_server/protocols/completed_analysis_store.py index 58017e4398a..5f72357050b 100644 --- a/robot-server/robot_server/protocols/completed_analysis_store.py +++ b/robot-server/robot_server/protocols/completed_analysis_store.py @@ -21,6 +21,8 @@ _log = getLogger(__name__) +MAX_ANALYSES_TO_STORE = 5 + @dataclass class CompletedAnalysisResource: @@ -334,13 +336,34 @@ def get_ids_by_protocol(self, protocol_id: str) -> List[str]: return result_ids - async def add(self, completed_analysis_resource: CompletedAnalysisResource) -> None: - """Add a resource to the store.""" - statement = analysis_table.insert().values( + async def make_room_and_add( + self, completed_analysis_resource: CompletedAnalysisResource + ) -> None: + """Make room and add a resource to the store. + + Removes the oldest analyses in store if the number of analyses exceed + the max allowed, and then adds the new analysis. + """ + analyses_ids = self.get_ids_by_protocol(completed_analysis_resource.protocol_id) + + # Delete all analyses exceeding max number allowed, + # plus an additional one to create room for the new one. + # Most existing databases will not have multiple extra analyses per protocol + # but there would be some internally that added multiple analyses before + # we started capping the number of analyses. + analyses_to_delete = analyses_ids[: -MAX_ANALYSES_TO_STORE + 1] + for analysis_id in analyses_to_delete: + self._memcache.remove(analysis_id) + delete_statement = analysis_table.delete().where( + analysis_table.c.id.in_(analyses_to_delete) + ) + + insert_statement = analysis_table.insert().values( await completed_analysis_resource.to_sql_values() ) with self._sql_engine.begin() as transaction: - transaction.execute(statement) + transaction.execute(delete_statement) + transaction.execute(insert_statement) self._memcache.insert( completed_analysis_resource.id, completed_analysis_resource ) diff --git a/robot-server/robot_server/runs/engine_store.py b/robot-server/robot_server/runs/engine_store.py index 8a35c20d92f..5b6d57520a7 100644 --- a/robot-server/robot_server/runs/engine_store.py +++ b/robot-server/robot_server/runs/engine_store.py @@ -1,6 +1,9 @@ """In-memory storage of ProtocolEngine instances.""" +import asyncio +import logging from typing import List, NamedTuple, Optional, Callable +from opentrons.protocol_engine.errors.exceptions import EStopActivatedError from opentrons.protocol_engine.types import PostRunHardwareState from opentrons_shared_data.robot.dev_types import RobotType from opentrons_shared_data.robot.dev_types import RobotTypeEnum @@ -38,6 +41,9 @@ ) +_log = logging.getLogger(__name__) + + class EngineConflictError(RuntimeError): """An error raised if an active engine is already initialized. @@ -58,18 +64,45 @@ class RunnerEnginePair(NamedTuple): engine: ProtocolEngine -def get_estop_listener(engine_store: "EngineStore") -> HardwareEventHandler: - """Create a callback for estop events.""" +async def handle_estop_event(engine_store: "EngineStore", event: HardwareEvent) -> None: + """Handle an E-stop event from the hardware API. + + This is meant to run in the engine's thread and asyncio event loop. - def _callback(event: HardwareEvent) -> None: + This is a public function for unit-testing purposes, but it's an implementation + detail of the store. + """ + try: if isinstance(event, EstopStateNotification): if event.new_state is not EstopState.PHYSICALLY_ENGAGED: return if engine_store.current_run_id is None: return - engine_store.engine.estop(maintenance_run=False) + # todo(mm, 2024-04-17): This estop teardown sequencing belongs in the + # runner layer. + engine_store.engine.estop() + await engine_store.engine.finish(error=EStopActivatedError()) + except Exception: + # This is a background task kicked off by a hardware event, + # so there's no one to propagate this exception to. + _log.exception("Exception handling E-stop event.") + + +def _get_estop_listener(engine_store: "EngineStore") -> HardwareEventHandler: + """Create a callback for estop events. + + The returned callback is meant to run in the hardware API's thread. + """ + engine_loop = asyncio.get_running_loop() + + def run_handler_in_engine_thread_from_hardware_thread( + event: HardwareEvent, + ) -> None: + asyncio.run_coroutine_threadsafe( + handle_estop_event(engine_store, event), engine_loop + ) - return _callback + return run_handler_in_engine_thread_from_hardware_thread class EngineStore: @@ -94,7 +127,7 @@ def __init__( self._deck_type = deck_type self._default_engine: Optional[ProtocolEngine] = None self._runner_engine_pair: Optional[RunnerEnginePair] = None - hardware_api.register_callback(get_estop_listener(self)) + hardware_api.register_callback(_get_estop_listener(self)) @property def engine(self) -> ProtocolEngine: diff --git a/robot-server/robot_server/runs/router/actions_router.py b/robot-server/robot_server/runs/router/actions_router.py index b662d59f554..25aae8cfd19 100644 --- a/robot-server/robot_server/runs/router/actions_router.py +++ b/robot-server/robot_server/runs/router/actions_router.py @@ -28,6 +28,7 @@ MaintenanceEngineStore, ) from robot_server.maintenance_runs.dependencies import get_maintenance_engine_store +from robot_server.service.notifications import get_runs_publisher, RunsPublisher log = logging.getLogger(__name__) actions_router = APIRouter() @@ -45,6 +46,7 @@ async def get_run_controller( task_runner: TaskRunner = Depends(get_task_runner), engine_store: EngineStore = Depends(get_engine_store), run_store: RunStore = Depends(get_run_store), + runs_publisher: RunsPublisher = Depends(get_runs_publisher), ) -> RunController: """Get a RunController for the current run. @@ -67,6 +69,7 @@ async def get_run_controller( task_runner=task_runner, engine_store=engine_store, run_store=run_store, + runs_publisher=runs_publisher, ) diff --git a/robot-server/robot_server/runs/router/base_router.py b/robot-server/robot_server/runs/router/base_router.py index 728966823fb..375bc7bf556 100644 --- a/robot-server/robot_server/runs/router/base_router.py +++ b/robot-server/robot_server/runs/router/base_router.py @@ -45,7 +45,7 @@ get_deck_configuration_store, ) from robot_server.deck_configuration.store import DeckConfigurationStore -from robot_server.service.notifications import get_notify_publishers +from robot_server.service.notifications import get_pe_notify_publishers log = logging.getLogger(__name__) base_router = APIRouter() @@ -144,7 +144,7 @@ async def create_run( deck_configuration_store: DeckConfigurationStore = Depends( get_deck_configuration_store ), - notify_publishers: Callable[[], None] = Depends(get_notify_publishers), + notify_publishers: Callable[[], None] = Depends(get_pe_notify_publishers), ) -> PydanticResponse[SimpleBody[Union[Run, BadRun]]]: """Create a new run. diff --git a/robot-server/robot_server/runs/router/commands_router.py b/robot-server/robot_server/runs/router/commands_router.py index 734d1a26066..b220ae33c04 100644 --- a/robot-server/robot_server/runs/router/commands_router.py +++ b/robot-server/robot_server/runs/router/commands_router.py @@ -6,6 +6,7 @@ from anyio import move_on_after from fastapi import APIRouter, Depends, Query, status + from pydantic import BaseModel, Field from opentrons.protocol_engine import ( @@ -21,11 +22,12 @@ MultiBody, MultiBodyMeta, PydanticResponse, + SimpleMultiBody, ) from robot_server.robot.control.dependencies import require_estop_in_good_state from ..run_models import RunCommandSummary -from ..run_data_manager import RunDataManager +from ..run_data_manager import RunDataManager, PreSerializedCommandsNotAvailableError from ..engine_store import EngineStore from ..run_store import RunStore, CommandNotFoundError from ..run_models import RunNotFoundError @@ -56,11 +58,30 @@ class CommandNotFound(ErrorDetails): title: str = "Run Command Not Found" +class SetupCommandNotAllowed(ErrorDetails): + """An error if a given run setup command is not allowed.""" + + id: Literal["SetupCommandNotAllowed"] = "SetupCommandNotAllowed" + title: str = "Setup Command Not Allowed" + + class CommandNotAllowed(ErrorDetails): """An error if a given run command is not allowed.""" id: Literal["CommandNotAllowed"] = "CommandNotAllowed" - title: str = "Setup Command Not Allowed" + title: str = "Command Not Allowed" + + +class PreSerializedCommandsNotAvailable(ErrorDetails): + """An error if one tries to fetch pre-serialized commands before they are written to the database.""" + + id: Literal[ + "PreSerializedCommandsNotAvailable" + ] = "PreSerializedCommandsNotAvailable" + title: str = "Pre-Serialized commands not available." + detail: str = ( + "Pre-serialized commands are only available once a run has finished running." + ) class CommandLinkMeta(BaseModel): @@ -128,6 +149,7 @@ async def get_current_run_engine_from_url( - Setup commands (`data.source == "setup"`) - Protocol commands (`data.source == "protocol"`) + - Fixit commands (`data.source == "fixit"`) Setup commands may be enqueued before the run has been started. You could use setup commands to prepare a module or @@ -138,6 +160,11 @@ async def get_current_run_engine_from_url( If you are running a protocol from a file(s), then you will likely not need to enqueue protocol commands using this endpoint. + Fixit commands may be enqueued while the run is `awaiting-recovery` state. + These commands are intended to fix a failed command. + They will be executed right after the failed command + and only if the run is in a `awaiting-recovery` state. + Once enqueued, setup commands will execute immediately with priority, while protocol commands will wait until a `play` action is issued. A play action may be issued while setup commands are still queued, @@ -153,8 +180,9 @@ async def get_current_run_engine_from_url( status.HTTP_201_CREATED: {"model": SimpleBody[pe_commands.Command]}, status.HTTP_404_NOT_FOUND: {"model": ErrorBody[RunNotFound]}, status.HTTP_409_CONFLICT: { - "model": ErrorBody[Union[RunStopped, CommandNotAllowed]] + "model": ErrorBody[Union[RunStopped, SetupCommandNotAllowed]] }, + status.HTTP_400_BAD_REQUEST: {"model": ErrorBody[CommandNotAllowed]}, }, ) async def create_run_command( @@ -187,6 +215,12 @@ async def create_run_command( " the default was 30 seconds, not infinite." ), ), + failedCommandId: Optional[str] = Query( + default=None, + description=( + "FIXIT command use only. Reference of the failed command id we are trying to fix." + ), + ), protocol_engine: ProtocolEngine = Depends(get_current_run_engine_from_url), check_estop: bool = Depends(require_estop_in_good_state), ) -> PydanticResponse[SimpleBody[pe_commands.Command]]: @@ -199,6 +233,8 @@ async def create_run_command( Else, return immediately. Comes from a query parameter in the URL. timeout: The maximum time, in seconds, to wait before returning. Comes from a query parameter in the URL. + failedCommandId: FIXIT command use only. + Reference of the failed command id we are trying to fix. protocol_engine: The run's `ProtocolEngine` on which the new command will be enqueued. check_estop: Dependency to verify the estop is in a valid state. @@ -207,14 +243,17 @@ async def create_run_command( # behavior is to pass through `command_intent` without overriding it command_intent = request_body.data.intent or pe_commands.CommandIntent.SETUP command_create = request_body.data.copy(update={"intent": command_intent}) - try: - command = protocol_engine.add_command(command_create) + command = protocol_engine.add_command( + request=command_create, failed_command_id=failedCommandId + ) except pe_errors.SetupCommandNotAllowedError as e: - raise CommandNotAllowed.from_exc(e).as_error(status.HTTP_409_CONFLICT) + raise SetupCommandNotAllowed.from_exc(e).as_error(status.HTTP_409_CONFLICT) except pe_errors.RunStoppedError as e: raise RunStopped.from_exc(e).as_error(status.HTTP_409_CONFLICT) + except pe_errors.CommandNotAllowedError as e: + raise CommandNotAllowed.from_exc(e).as_error(status.HTTP_400_BAD_REQUEST) if waitUntilComplete: timeout_sec = None if timeout is None else timeout / 1000.0 @@ -326,6 +365,56 @@ async def get_run_commands( ) +# TODO (spp, 2024-05-01): explore alternatives to returning commands as list of strings. +# Options: 1. JSON Lines +# 2. Simple de-serialized commands list w/o pydantic model conversion +@PydanticResponse.wrap_route( + commands_router.get, + path="/runs/{runId}/commandsAsPreSerializedList", + summary="Get all commands of a completed run as a list of pre-serialized commands", + description=( + "Get all commands of a completed run as a list of pre-serialized commands." + "**Warning:** This endpoint is experimental. We may change or remove it without warning." + "\n\n" + "The commands list will only be available after a run has completed" + " (whether successful, failed or stopped) and its data has been committed to the database." + " If a request is received before the run is completed, it will return a 503 Unavailable error." + " This is a faster alternative to fetching the full commands list using" + " `GET /runs/{runId}/commands`. For large protocols (10k+ commands), the above" + " endpoint can take minutes to respond, whereas this one should only take a few seconds." + ), + responses={ + status.HTTP_404_NOT_FOUND: {"model": ErrorBody[RunNotFound]}, + status.HTTP_503_SERVICE_UNAVAILABLE: { + "model": ErrorBody[PreSerializedCommandsNotAvailable] + }, + }, +) +async def get_run_commands_as_pre_serialized_list( + runId: str, + run_data_manager: RunDataManager = Depends(get_run_data_manager), +) -> PydanticResponse[SimpleMultiBody[str]]: + """Get all commands of a completed run as a list of pre-serialized (string encoded) commands. + + Arguments: + runId: Requested run ID, from the URL + run_data_manager: Run data retrieval interface. + """ + try: + commands = run_data_manager.get_all_commands_as_preserialized_list(runId) + except RunNotFoundError as e: + raise RunNotFound.from_exc(e).as_error(status.HTTP_404_NOT_FOUND) from e + except PreSerializedCommandsNotAvailableError as e: + raise PreSerializedCommandsNotAvailable.from_exc(e).as_error( + status.HTTP_503_SERVICE_UNAVAILABLE + ) from e + return await PydanticResponse.create( + content=SimpleMultiBody.construct( + data=commands, meta=MultiBodyMeta(cursor=0, totalLength=len(commands)) + ) + ) + + @PydanticResponse.wrap_route( commands_router.get, path="/runs/{runId}/commands/{commandId}", diff --git a/robot-server/robot_server/runs/run_controller.py b/robot-server/robot_server/runs/run_controller.py index 782754c1da6..e7e55080aed 100644 --- a/robot-server/robot_server/runs/run_controller.py +++ b/robot-server/robot_server/runs/run_controller.py @@ -13,6 +13,8 @@ from opentrons.protocol_engine.types import DeckConfigurationType +from robot_server.service.notifications import RunsPublisher + log = logging.getLogger(__name__) @@ -21,7 +23,7 @@ class RunActionNotAllowedError(RoboticsInteractionError): class RunController: - """An interface to manage the side-effects of requested run actions.""" + """An interface to manage the side effects of requested run actions.""" def __init__( self, @@ -29,11 +31,13 @@ def __init__( task_runner: TaskRunner, engine_store: EngineStore, run_store: RunStore, + runs_publisher: RunsPublisher, ) -> None: self._run_id = run_id self._task_runner = task_runner self._engine_store = engine_store self._run_store = run_store + self._runs_publisher = runs_publisher def create_action( self, @@ -106,4 +110,8 @@ async def _run_protocol_and_insert_result( run_id=self._run_id, summary=result.state_summary, commands=result.commands, + run_time_parameters=result.parameters, + ) + await self._runs_publisher.publish_pre_serialized_commands_notification( + self._run_id ) diff --git a/robot-server/robot_server/runs/run_data_manager.py b/robot-server/robot_server/runs/run_data_manager.py index 570537a135c..311cfb93b40 100644 --- a/robot-server/robot_server/runs/run_data_manager.py +++ b/robot-server/robot_server/runs/run_data_manager.py @@ -22,13 +22,14 @@ from .run_store import RunResource, RunStore, BadRunResource, BadStateSummary from .run_models import Run, BadRun, RunDataError -from opentrons.protocol_engine.types import DeckConfigurationType +from opentrons.protocol_engine.types import DeckConfigurationType, RunTimeParameter def _build_run( run_resource: Union[RunResource, BadRunResource], state_summary: Union[StateSummary, BadStateSummary], current: bool, + run_time_parameters: List[RunTimeParameter], ) -> Union[Run, BadRun]: # TODO(mc, 2022-05-16): improve persistence strategy # such that this default summary object is not needed @@ -49,6 +50,7 @@ def _build_run( completedAt=state_summary.completedAt, startedAt=state_summary.startedAt, liquids=state_summary.liquids, + runTimeParameters=run_time_parameters, ) errors: List[EnumeratedError] = [] @@ -102,6 +104,7 @@ def _build_run( completedAt=state.completedAt, startedAt=state.startedAt, liquids=state.liquids, + runTimeParameters=run_time_parameters, ) @@ -109,6 +112,10 @@ class RunNotCurrentError(ValueError): """Error raised when a requested run is not the current run.""" +class PreSerializedCommandsNotAvailableError(LookupError): + """Error raised when a run's commands are not available as pre-serialized list of commands.""" + + class RunDataManager: """Collaborator to manage current and historical run data. @@ -172,6 +179,7 @@ async def create( run_id=prev_run_id, summary=prev_run_result.state_summary, commands=prev_run_result.commands, + run_time_parameters=prev_run_result.parameters, ) state_summary = await self._engine_store.create( run_id=run_id, @@ -196,6 +204,7 @@ async def create( run_resource=run_resource, state_summary=state_summary, current=True, + run_time_parameters=[], ) def get(self, run_id: str) -> Union[Run, BadRun]: @@ -215,9 +224,10 @@ def get(self, run_id: str) -> Union[Run, BadRun]: """ run_resource = self._run_store.get(run_id=run_id) state_summary = self._get_state_summary(run_id=run_id) + parameters = self._get_run_time_parameters(run_id=run_id) current = run_id == self._engine_store.current_run_id - return _build_run(run_resource, state_summary, current) + return _build_run(run_resource, state_summary, current, parameters) def get_run_loaded_labware_definitions( self, run_id: str @@ -260,6 +270,7 @@ def get_all(self, length: Optional[int]) -> List[Union[Run, BadRun]]: run_resource=run_resource, state_summary=self._get_state_summary(run_resource.run_id), current=run_resource.run_id == self._engine_store.current_run_id, + run_time_parameters=self._get_run_time_parameters(run_resource.run_id), ) for run_resource in self._run_store.get_all(length) ] @@ -277,15 +288,22 @@ async def delete(self, run_id: str) -> None: """ if run_id == self._engine_store.current_run_id: await self._engine_store.clear() - await self._runs_publisher.clean_up_current_run() + + await self._runs_publisher.clean_up_run(run_id=run_id) self._run_store.remove(run_id=run_id) async def update(self, run_id: str, current: Optional[bool]) -> Union[Run, BadRun]: - """Get and potentially archive a run. + """Get and potentially archive the current run. Args: run_id: The run to get and maybe archive. + current: Whether to mark the run as current or not. + If `current` set to False, then the run is 'un-current'ed by + stopping the run, saving the final run data to the run store, + and clearing the engine and runner. + If 'current' is True or not specified, we simply fetch the run's + data from memory and database. Returns: The updated run. @@ -310,15 +328,21 @@ async def update(self, run_id: str, current: Optional[bool]) -> Union[Run, BadRu run_id=run_id, summary=state_summary, commands=commands, + run_time_parameters=parameters, + ) + await self._runs_publisher.publish_pre_serialized_commands_notification( + run_id ) else: state_summary = self._engine_store.engine.state_view.get_summary() + parameters = self._engine_store.runner.run_time_parameters run_resource = self._run_store.get(run_id=run_id) return _build_run( run_resource=run_resource, state_summary=state_summary, current=next_current, + run_time_parameters=parameters, ) def get_commands_slice( @@ -376,6 +400,17 @@ def get_command(self, run_id: str, command_id: str) -> Command: return self._run_store.get_command(run_id=run_id, command_id=command_id) + def get_all_commands_as_preserialized_list(self, run_id: str) -> List[str]: + """Get all commands of a run in a serialized json list.""" + if ( + run_id == self._engine_store.current_run_id + and not self._engine_store.engine.state_view.commands.get_is_terminal() + ): + raise PreSerializedCommandsNotAvailableError( + "Pre-serialized commands are only available after a run has ended." + ) + return self._run_store.get_all_commands_as_preserialized_list(run_id) + def _get_state_summary(self, run_id: str) -> Union[StateSummary, BadStateSummary]: if run_id == self._engine_store.current_run_id: return self._engine_store.engine.state_view.get_summary() @@ -385,3 +420,9 @@ def _get_state_summary(self, run_id: str) -> Union[StateSummary, BadStateSummary def _get_good_state_summary(self, run_id: str) -> Optional[StateSummary]: summary = self._get_state_summary(run_id) return summary if isinstance(summary, StateSummary) else None + + def _get_run_time_parameters(self, run_id: str) -> List[RunTimeParameter]: + if run_id == self._engine_store.current_run_id: + return self._engine_store.runner.run_time_parameters + else: + return self._run_store.get_run_time_parameters(run_id=run_id) diff --git a/robot-server/robot_server/runs/run_models.py b/robot-server/robot_server/runs/run_models.py index 7da6e0b0a5d..c93049bfef4 100644 --- a/robot-server/robot_server/runs/run_models.py +++ b/robot-server/robot_server/runs/run_models.py @@ -18,7 +18,7 @@ Liquid, CommandNote, ) -from opentrons.protocol_engine.types import RunTimeParamValuesType +from opentrons.protocol_engine.types import RunTimeParameter, RunTimeParamValuesType from opentrons_shared_data.errors import GeneralError from robot_server.service.json_api import ResourceModel from robot_server.errors.error_responses import ErrorDetails @@ -121,6 +121,15 @@ class Run(ResourceModel): ..., description="Labware offsets to apply as labware are loaded.", ) + runTimeParameters: List[RunTimeParameter] = Field( + default_factory=list, + description=( + "Run time parameters used during the run." + " These are the parameters that are defined in the protocol, with values" + " specified either in the run creation request or default values from the protocol" + " if none are specified in the request." + ), + ) protocolId: Optional[str] = Field( None, description=( @@ -185,6 +194,15 @@ class BadRun(ResourceModel): ..., description="Labware offsets to apply as labware are loaded.", ) + runTimeParameters: List[RunTimeParameter] = Field( + default_factory=list, + description=( + "Run time parameters used during the run." + " These are the parameters that are defined in the protocol, with values" + " specified either in the run creation request or default values from the protocol" + " if none are specified in the request." + ), + ) protocolId: Optional[str] = Field( None, description=( diff --git a/robot-server/robot_server/runs/run_store.py b/robot-server/robot_server/runs/run_store.py index 5aa6dbae96b..6cf86d14af1 100644 --- a/robot-server/robot_server/runs/run_store.py +++ b/robot-server/robot_server/runs/run_store.py @@ -12,6 +12,7 @@ from opentrons.util.helpers import utc_now from opentrons.protocol_engine import StateSummary, CommandSlice from opentrons.protocol_engine.commands import Command +from opentrons.protocol_engine.types import RunTimeParameter from opentrons_shared_data.errors.exceptions import ( EnumeratedError, @@ -25,7 +26,12 @@ run_command_table, action_table, ) -from robot_server.persistence.pydantic import json_to_pydantic, pydantic_to_json +from robot_server.persistence.pydantic import ( + json_to_pydantic, + pydantic_to_json, + json_to_pydantic_list, + pydantic_list_to_json, +) from robot_server.protocols.protocol_store import ProtocolNotFoundError from .action_models import RunAction, RunActionType @@ -102,6 +108,7 @@ def update_run_state( run_id: str, summary: StateSummary, commands: List[Command], + run_time_parameters: List[RunTimeParameter], ) -> RunResource: """Update the run's state summary and commands list. @@ -109,6 +116,7 @@ def update_run_state( run_id: The run to update summary: The run's equipment and status summary. commands: The run's commands. + run_time_parameters: The run's run time parameters, if any. Returns: The run resource. @@ -124,6 +132,7 @@ def update_run_state( run_id=run_id, state_summary=summary, engine_status=summary.status, + run_time_parameters=run_time_parameters, ) ) ) @@ -346,6 +355,33 @@ def get_state_summary(self, run_id: str) -> Union[StateSummary, BadStateSummary] ) ) + @lru_cache(maxsize=_CACHE_ENTRIES) + def get_run_time_parameters(self, run_id: str) -> List[RunTimeParameter]: + """Get the archived run time parameters. + + This is a list of the run's parameter definitions (if any), + including the values used in the run itself, along with the default value, + constraints and associated names and descriptions. + """ + select_run_data = sqlalchemy.select(run_table.c.run_time_parameters).where( + run_table.c.id == run_id + ) + + with self._sql_engine.begin() as transaction: + row = transaction.execute(select_run_data).one() + + try: + return ( + json_to_pydantic_list(RunTimeParameter, row.run_time_parameters) # type: ignore[arg-type] + if row.run_time_parameters is not None + else [] + ) + except ValidationError: + log.warning( + f"Error retrieving run time parameters for {run_id}", exc_info=True + ) + return [] + def get_commands_slice( self, run_id: str, @@ -392,7 +428,6 @@ def get_commands_slice( ) .order_by(run_command_table.c.index_in_run) ) - slice_result = transaction.execute(select_slice).all() sliced_commands: List[Command] = [ @@ -406,6 +441,19 @@ def get_commands_slice( commands=sliced_commands, ) + def get_all_commands_as_preserialized_list(self, run_id: str) -> List[str]: + """Get all commands of the run as a list of strings of json command objects.""" + with self._sql_engine.begin() as transaction: + if not self._run_exists(run_id, transaction): + raise RunNotFoundError(run_id=run_id) + select_commands = ( + sqlalchemy.select(run_command_table.c.command) + .where(run_command_table.c.run_id == run_id) + .order_by(run_command_table.c.index_in_run) + ) + commands_result = transaction.scalars(select_commands).all() + return commands_result + @lru_cache(maxsize=_CACHE_ENTRIES) def get_command(self, run_id: str, command_id: str) -> Command: """Get run command by id. @@ -476,6 +524,7 @@ def _clear_caches(self) -> None: self.get_all.cache_clear() self.get_state_summary.cache_clear() self.get_command.cache_clear() + self.get_run_time_parameters.cache_clear() # The columns that must be present in a row passed to _convert_row_to_run(). @@ -552,9 +601,11 @@ def _convert_state_to_sql_values( run_id: str, state_summary: StateSummary, engine_status: str, + run_time_parameters: List[RunTimeParameter], ) -> Dict[str, object]: return { "state_summary": pydantic_to_json(state_summary), "engine_status": engine_status, "_updated_at": utc_now(), + "run_time_parameters": pydantic_list_to_json(run_time_parameters), } diff --git a/robot-server/robot_server/service/legacy/routers/settings.py b/robot-server/robot_server/service/legacy/routers/settings.py index 16a732ff97f..5d79053d696 100644 --- a/robot-server/robot_server/service/legacy/routers/settings.py +++ b/robot-server/robot_server/service/legacy/routers/settings.py @@ -1,7 +1,7 @@ -from dataclasses import asdict +import aiohttp import logging +from dataclasses import asdict from typing import cast, Any, Dict, List, Optional, Union - from starlette import status from fastapi import APIRouter, Depends @@ -32,7 +32,6 @@ from robot_server.errors.error_responses import LegacyErrorResponse from robot_server.hardware import ( get_hardware, - get_robot_type, get_robot_type_enum, get_ot2_hardware, ) @@ -64,6 +63,17 @@ router = APIRouter() +# TODO: (ba, 2024-04-11): We should have a proper IPC mechanism to talk between +# the servers instead of one off endpoint calls like these. +async def set_oem_mode_request(enable): + """PUT request to set the OEM Mode for the system server.""" + async with aiohttp.ClientSession() as session: + async with session.put( + "http://127.0.0.1:31950/system/oem_mode/enable", json={"enable": enable} + ) as resp: + return resp.status + + @router.post( path="/settings", summary="Change a setting", @@ -78,10 +88,17 @@ async def post_settings( update: AdvancedSettingRequest, hardware: HardwareControlAPI = Depends(get_hardware), - robot_type: str = Depends(get_robot_type), + robot_type: RobotTypeEnum = Depends(get_robot_type_enum), ) -> AdvancedSettingsResponse: """Update advanced setting (feature flag)""" try: + # send request to system server if this is the enableOEMMode setting + if update.id == "enableOEMMode" and robot_type == RobotTypeEnum.FLEX: + resp = await set_oem_mode_request(update.value) + if resp != 200: + # TODO: raise correct error here + raise Exception(f"Something went wrong setting OEM Mode. err: {resp}") + await advanced_settings.set_adv_setting(update.id, update.value) hardware.hardware_feature_flags = HardwareFeatureFlags.build_from_ff() await hardware.set_status_bar_enabled(ff.status_bar_enabled()) @@ -104,21 +121,15 @@ async def post_settings( response_model_exclude_unset=True, ) async def get_settings( - robot_type: str = Depends(get_robot_type), + robot_type: RobotTypeEnum = Depends(get_robot_type_enum), ) -> AdvancedSettingsResponse: """Get advanced setting (feature flags)""" return _create_settings_response(robot_type) -def _create_settings_response(robot_type: str) -> AdvancedSettingsResponse: +def _create_settings_response(robot_type: RobotTypeEnum) -> AdvancedSettingsResponse: """Create the feature flag settings response object""" - # TODO lc(8-10-2023) We should convert the robot type function to return - # the enum value directly. - if robot_type == "OT-2 Standard": - robot_type_enum = RobotTypeEnum.OT2 - else: - robot_type_enum = RobotTypeEnum.FLEX - data = advanced_settings.get_all_adv_settings(robot_type_enum) + data = advanced_settings.get_all_adv_settings(robot_type) if advanced_settings.is_restart_required(): links = Links(restart="/server/restart") diff --git a/robot-server/robot_server/service/notifications/__init__.py b/robot-server/robot_server/service/notifications/__init__.py index 7fd648f32aa..e62402f06f5 100644 --- a/robot-server/robot_server/service/notifications/__init__.py +++ b/robot-server/robot_server/service/notifications/__init__.py @@ -6,14 +6,15 @@ get_notification_client, clean_up_notification_client, ) -from .publisher_notifier import PublisherNotifier, get_notify_publishers +from .publisher_notifier import PublisherNotifier, get_pe_notify_publishers from .publishers import ( MaintenanceRunsPublisher, RunsPublisher, + DeckConfigurationPublisher, get_maintenance_runs_publisher, get_runs_publisher, + get_deck_configuration_publisher, ) -from .change_notifier import ChangeNotifier from .topics import Topics __all__ = [ @@ -22,16 +23,17 @@ # notification "route" equivalents "MaintenanceRunsPublisher", "RunsPublisher", + "DeckConfigurationPublisher", # initialization and teardown "initialize_notifications", "clean_up_notification_client", # for use by FastAPI "get_notification_client", - "get_notify_publishers", + "get_pe_notify_publishers", "get_maintenance_runs_publisher", "get_runs_publisher", + "get_deck_configuration_publisher", # for testing "PublisherNotifier", - "ChangeNotifier", "Topics", ] diff --git a/robot-server/robot_server/service/notifications/change_notifier.py b/robot-server/robot_server/service/notifications/change_notifier.py deleted file mode 100644 index 60c36c420af..00000000000 --- a/robot-server/robot_server/service/notifications/change_notifier.py +++ /dev/null @@ -1,23 +0,0 @@ -"""Simple state change notification interface.""" -import asyncio - - -class ChangeNotifier: - """An interface to emit or subscribe to state change notifications.""" - - def __init__(self) -> None: - """Initialize the ChangeNotifier with an internal Event.""" - self._event = asyncio.Event() - - def notify(self) -> None: - """Notify all `waiters` of a change.""" - self._event.set() - - async def wait(self) -> None: - """Wait until the next change notification.""" - self._event.clear() - await self._event.wait() - - def clear(self) -> None: - """Reset the internal event flag.""" - self._event.clear() diff --git a/robot-server/robot_server/service/notifications/initialize_notifications.py b/robot-server/robot_server/service/notifications/initialize_notifications.py index d5569d09eff..3691ba1a668 100644 --- a/robot-server/robot_server/service/notifications/initialize_notifications.py +++ b/robot-server/robot_server/service/notifications/initialize_notifications.py @@ -2,10 +2,10 @@ from server_utils.fastapi_utils.app_state import AppState from .notification_client import initialize_notification_client -from .publisher_notifier import initialize_publisher_notifier +from .publisher_notifier import initialize_pe_publisher_notifier async def initialize_notifications(app_state: AppState) -> None: """Initialize the notification system for the given app state.""" initialize_notification_client(app_state) - await initialize_publisher_notifier(app_state) + await initialize_pe_publisher_notifier(app_state) diff --git a/robot-server/robot_server/service/notifications/publisher_notifier.py b/robot-server/robot_server/service/notifications/publisher_notifier.py index d1769ac4379..22b5c34b79e 100644 --- a/robot-server/robot_server/service/notifications/publisher_notifier.py +++ b/robot-server/robot_server/service/notifications/publisher_notifier.py @@ -1,7 +1,7 @@ """Provides an interface for alerting notification publishers to events and related lifecycle utilities.""" import asyncio from fastapi import Depends -from typing import Optional, Callable, List, Awaitable +from typing import Optional, Callable, List, Awaitable, Union from server_utils.fastapi_utils.app_state import ( AppState, @@ -9,18 +9,15 @@ get_app_state, ) -from .change_notifier import ChangeNotifier +from opentrons.util.change_notifier import ChangeNotifier, ChangeNotifier_ts class PublisherNotifier: """An interface that invokes notification callbacks whenever a generic notify event occurs.""" - def __init__( - self, - change_notifier: Optional[ChangeNotifier] = None, - ): - self._change_notifier = change_notifier or ChangeNotifier() - self._pe_notifier: Optional[asyncio.Task[None]] = None + def __init__(self, change_notifier: Union[ChangeNotifier, ChangeNotifier_ts]): + self._change_notifier = change_notifier + self._notifier: Optional[asyncio.Task[None]] = None self._callbacks: List[Callable[[], Awaitable[None]]] = [] def register_publish_callbacks( @@ -31,7 +28,7 @@ def register_publish_callbacks( async def _initialize(self) -> None: """Initializes an instance of PublisherNotifier. This method should only be called once.""" - self._pe_notifier = asyncio.create_task(self._wait_for_event()) + self._notifier = asyncio.create_task(self._wait_for_event()) def _notify_publishers(self) -> None: """A generic notifier, alerting all `waiters` of a change.""" @@ -45,37 +42,39 @@ async def _wait_for_event(self) -> None: await callback() -_publisher_notifier_accessor: AppStateAccessor[PublisherNotifier] = AppStateAccessor[ +_pe_publisher_notifier_accessor: AppStateAccessor[PublisherNotifier] = AppStateAccessor[ PublisherNotifier ]("publisher_notifier") -def get_publisher_notifier( +def get_pe_publisher_notifier( app_state: AppState = Depends(get_app_state), ) -> PublisherNotifier: - """Intended for use by various publishers only.""" - publisher_notifier = _publisher_notifier_accessor.get_from(app_state) + """Intended for use by various publishers only. Intended for protocol engine.""" + publisher_notifier = _pe_publisher_notifier_accessor.get_from(app_state) assert publisher_notifier is not None return publisher_notifier -def get_notify_publishers( +def get_pe_notify_publishers( app_state: AppState = Depends(get_app_state), ) -> Callable[[], None]: - """Provides access to the callback used to notify publishers of changes.""" - publisher_notifier = _publisher_notifier_accessor.get_from(app_state) + """Provides access to the callback used to notify publishers of changes. Intended for protocol engine.""" + publisher_notifier = _pe_publisher_notifier_accessor.get_from(app_state) assert isinstance(publisher_notifier, PublisherNotifier) return publisher_notifier._notify_publishers -async def initialize_publisher_notifier(app_state: AppState) -> None: +async def initialize_pe_publisher_notifier(app_state: AppState) -> None: """Create a new `NotificationClient` and store it on `app_state`. Intended to be called just once, when the server starts up. """ - publisher_notifier: PublisherNotifier = PublisherNotifier() - _publisher_notifier_accessor.set_on(app_state, publisher_notifier) + publisher_notifier: PublisherNotifier = PublisherNotifier( + change_notifier=ChangeNotifier() + ) + _pe_publisher_notifier_accessor.set_on(app_state, publisher_notifier) await publisher_notifier._initialize() diff --git a/robot-server/robot_server/service/notifications/publishers/__init__.py b/robot-server/robot_server/service/notifications/publishers/__init__.py index 59a30e7a135..813e8c62bc4 100644 --- a/robot-server/robot_server/service/notifications/publishers/__init__.py +++ b/robot-server/robot_server/service/notifications/publishers/__init__.py @@ -8,12 +8,18 @@ get_maintenance_runs_publisher, ) from .runs_publisher import RunsPublisher, get_runs_publisher +from .deck_configuration_publisher import ( + DeckConfigurationPublisher, + get_deck_configuration_publisher, +) __all__ = [ # publish "route" equivalents "MaintenanceRunsPublisher", "RunsPublisher", + "DeckConfigurationPublisher", # for use by FastAPI "get_maintenance_runs_publisher", "get_runs_publisher", + "get_deck_configuration_publisher", ] diff --git a/robot-server/robot_server/service/notifications/publishers/deck_configuration_publisher.py b/robot-server/robot_server/service/notifications/publishers/deck_configuration_publisher.py new file mode 100644 index 00000000000..a1c0bc1e9a5 --- /dev/null +++ b/robot-server/robot_server/service/notifications/publishers/deck_configuration_publisher.py @@ -0,0 +1,48 @@ +from fastapi import Depends + +from server_utils.fastapi_utils.app_state import ( + AppState, + AppStateAccessor, + get_app_state, +) +from ..notification_client import NotificationClient, get_notification_client +from ..topics import Topics + + +class DeckConfigurationPublisher: + """Publishes deck configuration topics.""" + + def __init__(self, client: NotificationClient) -> None: + """Returns a configured Deck Configuration Publisher.""" + self._client = client + + async def publish_deck_configuration( + self, + ) -> None: + """Publishes the equivalent of GET /deck_configuration""" + await self._client.publish_advise_refetch_async(topic=Topics.DECK_CONFIGURATION) + + +_deck_configuration_publisher_accessor: AppStateAccessor[ + DeckConfigurationPublisher +] = AppStateAccessor[DeckConfigurationPublisher]("deck_configuration_publisher") + + +async def get_deck_configuration_publisher( + app_state: AppState = Depends(get_app_state), + notification_client: NotificationClient = Depends(get_notification_client), +) -> DeckConfigurationPublisher: + """Get a singleton DeckConfigurationPublisher to publish deck configuration topics.""" + deck_configuration_publisher = _deck_configuration_publisher_accessor.get_from( + app_state + ) + + if deck_configuration_publisher is None: + deck_configuration_publisher = DeckConfigurationPublisher( + client=notification_client + ) + _deck_configuration_publisher_accessor.set_on( + app_state, deck_configuration_publisher + ) + + return deck_configuration_publisher diff --git a/robot-server/robot_server/service/notifications/publishers/runs_publisher.py b/robot-server/robot_server/service/notifications/publishers/runs_publisher.py index b6744fbc90a..056877b7ec6 100644 --- a/robot-server/robot_server/service/notifications/publishers/runs_publisher.py +++ b/robot-server/robot_server/service/notifications/publishers/runs_publisher.py @@ -11,7 +11,7 @@ get_app_state, ) from ..notification_client import NotificationClient, get_notification_client -from ..publisher_notifier import PublisherNotifier, get_publisher_notifier +from ..publisher_notifier import PublisherNotifier, get_pe_publisher_notifier from ..topics import Topics @@ -71,12 +71,12 @@ async def initialize( ) self._engine_state_slice = EngineStateSlice() - await self._publish_runs_advise_refetch_async() + await self._publish_runs_advise_refetch_async(run_id=run_id) - async def clean_up_current_run(self) -> None: - """Publish final refetch and unsubscribe flags.""" - await self._publish_runs_advise_refetch_async() - await self._publish_runs_advise_unsubscribe_async() + async def clean_up_run(self, run_id: str) -> None: + """Publish final refetch and unsubscribe flags for the given run.""" + await self._publish_runs_advise_refetch_async(run_id=run_id) + await self._publish_runs_advise_unsubscribe_async(run_id=run_id) async def _publish_current_command(self) -> None: """Publishes the equivalent of GET /runs/:runId/commands?cursor=null&pageLength=1.""" @@ -84,19 +84,33 @@ async def _publish_current_command(self) -> None: topic=Topics.RUNS_CURRENT_COMMAND ) - async def _publish_runs_advise_refetch_async(self) -> None: + async def _publish_runs_advise_refetch_async(self, run_id: str) -> None: """Publish a refetch flag for relevant runs topics.""" + await self._client.publish_advise_refetch_async(topic=Topics.RUNS) + if self._run_hooks is not None: - await self._client.publish_advise_refetch_async(topic=Topics.RUNS) await self._client.publish_advise_refetch_async( - topic=f"{Topics.RUNS}/{self._run_hooks.run_id}" + topic=f"{Topics.RUNS}/{run_id}" ) - async def _publish_runs_advise_unsubscribe_async(self) -> None: + async def _publish_runs_advise_unsubscribe_async(self, run_id: str) -> None: """Publish an unsubscribe flag for relevant runs topics.""" if self._run_hooks is not None: await self._client.publish_advise_unsubscribe_async( - topic=f"{Topics.RUNS}/{self._run_hooks.run_id}" + topic=f"{Topics.RUNS}/{run_id}" + ) + await self._client.publish_advise_unsubscribe_async( + topic=Topics.RUNS_CURRENT_COMMAND + ) + await self._client.publish_advise_unsubscribe_async( + topic=f"{Topics.RUNS_PRE_SERIALIZED_COMMANDS}/{run_id}" + ) + + async def publish_pre_serialized_commands_notification(self, run_id: str) -> None: + """Publishes notification for GET /runs/:runId/commandsAsPreSerializedList.""" + if self._run_hooks is not None: + await self._client.publish_advise_refetch_async( + topic=f"{Topics.RUNS_PRE_SERIALIZED_COMMANDS}/{run_id}" ) async def _handle_current_command_change(self) -> None: @@ -121,7 +135,9 @@ async def _handle_engine_status_change(self) -> None: and self._engine_state_slice.state_summary_status != current_state_summary.status ): - await self._publish_runs_advise_refetch_async() + await self._publish_runs_advise_refetch_async( + run_id=self._run_hooks.run_id + ) self._engine_state_slice.state_summary_status = ( current_state_summary.status ) @@ -135,7 +151,7 @@ async def _handle_engine_status_change(self) -> None: async def get_runs_publisher( app_state: AppState = Depends(get_app_state), notification_client: NotificationClient = Depends(get_notification_client), - publisher_notifier: PublisherNotifier = Depends(get_publisher_notifier), + publisher_notifier: PublisherNotifier = Depends(get_pe_publisher_notifier), ) -> RunsPublisher: """Get a singleton RunsPublisher to publish runs topics.""" runs_publisher = _runs_publisher_accessor.get_from(app_state) diff --git a/robot-server/robot_server/service/notifications/topics.py b/robot-server/robot_server/service/notifications/topics.py index 34f2fd0eea1..f8a6ecaf701 100644 --- a/robot-server/robot_server/service/notifications/topics.py +++ b/robot-server/robot_server/service/notifications/topics.py @@ -14,3 +14,5 @@ class Topics(str, Enum): MAINTENANCE_RUNS_CURRENT_RUN = f"{_TOPIC_BASE}/maintenance_runs/current_run" RUNS_CURRENT_COMMAND = f"{_TOPIC_BASE}/runs/current_command" RUNS = f"{_TOPIC_BASE}/runs" + DECK_CONFIGURATION = f"{_TOPIC_BASE}/deck_configuration" + RUNS_PRE_SERIALIZED_COMMANDS = f"{_TOPIC_BASE}/runs/pre_serialized_commands" diff --git a/robot-server/robot_server/subsystems/firmware_update_manager.py b/robot-server/robot_server/subsystems/firmware_update_manager.py index 12aacc4feb4..43394e972ee 100644 --- a/robot-server/robot_server/subsystems/firmware_update_manager.py +++ b/robot-server/robot_server/subsystems/firmware_update_manager.py @@ -139,12 +139,13 @@ def __init__( created_at: datetime, update_id: str, complete_callback: Callable[[], Awaitable[None]], + status_cache: Optional[UpdateProgress] = None, ) -> None: """Build an _UpdateProcess. Should only be done by the manager.""" self._status_queue = Queue() self._hw_handle = hw_handle self._subsystem = subsystem - self._status_cache = None + self._status_cache = status_cache self._status_cache_lock = Lock() self._created_at = created_at self._update_id = update_id @@ -346,7 +347,12 @@ async def _complete() -> None: log.exception(f"Double pop for update on {subsystem}") self._all_updates_by_id[update_id] = _UpdateProcess( - self._hardware_handle, hw_subsystem, creation_time, update_id, _complete + self._hardware_handle, + hw_subsystem, + creation_time, + update_id, + _complete, + UpdateProgress(UpdateState.queued, 0, None), ) self._running_updates_by_subsystem[hw_subsystem] = self._all_updates_by_id[ update_id diff --git a/robot-server/simulators/test-flex.json b/robot-server/simulators/test-flex.json index d7fc860c662..adc9543fc5a 100644 --- a/robot-server/simulators/test-flex.json +++ b/robot-server/simulators/test-flex.json @@ -91,4 +91,4 @@ } ] } -} \ No newline at end of file +} diff --git a/robot-server/tests/deck_configuration/test_defaults.py b/robot-server/tests/deck_configuration/test_defaults.py index ec3bbed3c22..42aa3672f52 100644 --- a/robot-server/tests/deck_configuration/test_defaults.py +++ b/robot-server/tests/deck_configuration/test_defaults.py @@ -12,7 +12,7 @@ from robot_server.deck_configuration import validation_mapping -DECK_DEFINITION_VERSION: Final = 4 +DECK_DEFINITION_VERSION: Final = 5 @pytest.mark.parametrize( diff --git a/robot-server/tests/deck_configuration/test_validation.py b/robot-server/tests/deck_configuration/test_validation.py index 5aee74491da..24aecf9117a 100644 --- a/robot-server/tests/deck_configuration/test_validation.py +++ b/robot-server/tests/deck_configuration/test_validation.py @@ -7,22 +7,26 @@ def test_valid() -> None: """It should return an empty error list if the input is valid.""" - deck_definition = load_deck_definition("ot3_standard", version=4) + deck_definition = load_deck_definition("ot3_standard", version=5) cutout_fixtures = [ - subject.Placement(cutout_fixture_id=cutout_fixture_id, cutout_id=cutout_id) - for cutout_fixture_id, cutout_id in [ - ("singleLeftSlot", "cutoutA1"), - ("singleLeftSlot", "cutoutB1"), - ("singleLeftSlot", "cutoutC1"), - ("singleLeftSlot", "cutoutD1"), - ("singleCenterSlot", "cutoutA2"), - ("singleCenterSlot", "cutoutB2"), - ("singleCenterSlot", "cutoutC2"), - ("singleCenterSlot", "cutoutD2"), - ("stagingAreaRightSlot", "cutoutA3"), - ("singleRightSlot", "cutoutB3"), - ("stagingAreaRightSlot", "cutoutC3"), - ("singleRightSlot", "cutoutD3"), + subject.Placement( + cutout_fixture_id=cutout_fixture_id, + cutout_id=cutout_id, + opentrons_module_serial_number=opentrons_module_serial_number, + ) + for cutout_fixture_id, cutout_id, opentrons_module_serial_number in [ + ("singleLeftSlot", "cutoutA1", None), + ("singleLeftSlot", "cutoutB1", None), + ("singleLeftSlot", "cutoutC1", None), + ("singleLeftSlot", "cutoutD1", None), + ("singleCenterSlot", "cutoutA2", None), + ("singleCenterSlot", "cutoutB2", None), + ("singleCenterSlot", "cutoutC2", None), + ("singleCenterSlot", "cutoutD2", None), + ("stagingAreaRightSlot", "cutoutA3", None), + ("singleRightSlot", "cutoutB3", None), + ("stagingAreaRightSlot", "cutoutC3", None), + ("singleRightSlot", "cutoutD3", None), ] ] assert subject.get_configuration_errors(deck_definition, cutout_fixtures) == set() @@ -30,23 +34,27 @@ def test_valid() -> None: def test_invalid_empty_cutouts() -> None: """It should enforce that every cutout is occupied.""" - deck_definition = load_deck_definition("ot3_standard", version=4) + deck_definition = load_deck_definition("ot3_standard", version=5) cutout_fixtures = [ - subject.Placement(cutout_fixture_id=cutout_fixture_id, cutout_id=cutout_id) - for cutout_fixture_id, cutout_id in [ - ("singleLeftSlot", "cutoutA1"), - ("singleLeftSlot", "cutoutB1"), - ("singleLeftSlot", "cutoutC1"), - ("singleLeftSlot", "cutoutD1"), - ("singleCenterSlot", "cutoutA2"), - ("singleCenterSlot", "cutoutB2"), + subject.Placement( + cutout_fixture_id=cutout_fixture_id, + cutout_id=cutout_id, + opentrons_module_serial_number=opentrons_module_serial_number, + ) + for cutout_fixture_id, cutout_id, opentrons_module_serial_number in [ + ("singleLeftSlot", "cutoutA1", None), + ("singleLeftSlot", "cutoutB1", None), + ("singleLeftSlot", "cutoutC1", None), + ("singleLeftSlot", "cutoutD1", None), + ("singleCenterSlot", "cutoutA2", None), + ("singleCenterSlot", "cutoutB2", None), # Invalid because we haven't placed anything into cutout C2 or D2. - # ("singleCenterSlot", "cutoutC2"), - # ("singleCenterSlot", "cutoutD2"), - ("stagingAreaRightSlot", "cutoutA3"), - ("singleRightSlot", "cutoutB3"), - ("stagingAreaRightSlot", "cutoutC3"), - ("singleRightSlot", "cutoutD3"), + # ("singleCenterSlot", "cutoutC2", None), + # ("singleCenterSlot", "cutoutD2", None), + ("stagingAreaRightSlot", "cutoutA3", None), + ("singleRightSlot", "cutoutB3", None), + ("stagingAreaRightSlot", "cutoutC3", None), + ("singleRightSlot", "cutoutD3", None), ] ] assert subject.get_configuration_errors(deck_definition, cutout_fixtures) == { @@ -57,26 +65,30 @@ def test_invalid_empty_cutouts() -> None: def test_invalid_overcrowded_cutouts() -> None: """It should prevent you from putting multiple things into a single cutout.""" - deck_definition = load_deck_definition("ot3_standard", version=4) + deck_definition = load_deck_definition("ot3_standard", version=5) cutout_fixtures = [ - subject.Placement(cutout_fixture_id=cutout_fixture_id, cutout_id=cutout_id) - for cutout_fixture_id, cutout_id in [ - ("singleLeftSlot", "cutoutA1"), - ("singleLeftSlot", "cutoutB1"), - ("singleLeftSlot", "cutoutC1"), - ("singleLeftSlot", "cutoutD1"), - ("singleCenterSlot", "cutoutA2"), - ("singleCenterSlot", "cutoutB2"), - ("singleCenterSlot", "cutoutC2"), - ("singleCenterSlot", "cutoutD2"), - ("stagingAreaRightSlot", "cutoutA3"), - ("singleRightSlot", "cutoutB3"), + subject.Placement( + cutout_fixture_id=cutout_fixture_id, + cutout_id=cutout_id, + opentrons_module_serial_number=opentrons_module_serial_number, + ) + for cutout_fixture_id, cutout_id, opentrons_module_serial_number in [ + ("singleLeftSlot", "cutoutA1", None), + ("singleLeftSlot", "cutoutB1", None), + ("singleLeftSlot", "cutoutC1", None), + ("singleLeftSlot", "cutoutD1", None), + ("singleCenterSlot", "cutoutA2", None), + ("singleCenterSlot", "cutoutB2", None), + ("singleCenterSlot", "cutoutC2", None), + ("singleCenterSlot", "cutoutD2", None), + ("stagingAreaRightSlot", "cutoutA3", None), + ("singleRightSlot", "cutoutB3", None), # Invalid because we're placing two things in cutout C3... - ("stagingAreaRightSlot", "cutoutC3"), - ("stagingAreaRightSlot", "cutoutC3"), + ("stagingAreaRightSlot", "cutoutC3", None), + ("stagingAreaRightSlot", "cutoutC3", None), # ...and two things in cutout D3. - ("wasteChuteRightAdapterNoCover", "cutoutD3"), - ("singleRightSlot", "cutoutD3"), + ("wasteChuteRightAdapterNoCover", "cutoutD3", None), + ("singleRightSlot", "cutoutD3", None), ] ] assert subject.get_configuration_errors(deck_definition, cutout_fixtures) == { @@ -93,24 +105,28 @@ def test_invalid_overcrowded_cutouts() -> None: def test_invalid_cutout_for_fixture() -> None: """Each fixture must be placed in a location that's valid for that particular fixture.""" - deck_definition = load_deck_definition("ot3_standard", version=4) + deck_definition = load_deck_definition("ot3_standard", version=5) cutout_fixtures = [ - subject.Placement(cutout_fixture_id=cutout_fixture_id, cutout_id=cutout_id) - for cutout_fixture_id, cutout_id in [ - ("singleLeftSlot", "cutoutA1"), - ("singleLeftSlot", "cutoutB1"), - ("singleLeftSlot", "cutoutC1"), - ("singleLeftSlot", "cutoutD1"), - ("singleCenterSlot", "cutoutA2"), - ("singleCenterSlot", "cutoutB2"), + subject.Placement( + cutout_fixture_id=cutout_fixture_id, + cutout_id=cutout_id, + opentrons_module_serial_number=opentrons_module_serial_number, + ) + for cutout_fixture_id, cutout_id, opentrons_module_serial_number in [ + ("singleLeftSlot", "cutoutA1", None), + ("singleLeftSlot", "cutoutB1", None), + ("singleLeftSlot", "cutoutC1", None), + ("singleLeftSlot", "cutoutD1", None), + ("singleCenterSlot", "cutoutA2", None), + ("singleCenterSlot", "cutoutB2", None), # Invalid because wasteChuteRightAdapterNoCover can't be placed in cutout C2... - ("wasteChuteRightAdapterNoCover", "cutoutC2"), + ("wasteChuteRightAdapterNoCover", "cutoutC2", None), # ...nor can singleLeftSlot be placed in cutout D2. - ("singleLeftSlot", "cutoutD2"), - ("stagingAreaRightSlot", "cutoutA3"), - ("singleRightSlot", "cutoutB3"), - ("stagingAreaRightSlot", "cutoutC3"), - ("singleRightSlot", "cutoutD3"), + ("singleLeftSlot", "cutoutD2", None), + ("stagingAreaRightSlot", "cutoutA3", None), + ("singleRightSlot", "cutoutB3", None), + ("stagingAreaRightSlot", "cutoutC3", None), + ("singleRightSlot", "cutoutD3", None), ] ] assert subject.get_configuration_errors(deck_definition, cutout_fixtures) == { @@ -131,24 +147,28 @@ def test_invalid_cutout_for_fixture() -> None: def test_unrecognized_cutout() -> None: """It should raise a sensible error if you pass a totally nonexistent cutout.""" - deck_definition = load_deck_definition("ot3_standard", version=4) + deck_definition = load_deck_definition("ot3_standard", version=5) cutout_fixtures = [ - subject.Placement(cutout_fixture_id=cutout_fixture_id, cutout_id=cutout_id) - for cutout_fixture_id, cutout_id in [ - ("singleLeftSlot", "cutoutA1"), - ("singleLeftSlot", "cutoutB1"), - ("singleLeftSlot", "cutoutC1"), - ("singleLeftSlot", "cutoutD1"), - ("singleCenterSlot", "cutoutA2"), - ("singleCenterSlot", "cutoutB2"), - ("singleCenterSlot", "cutoutC2"), - ("singleCenterSlot", "cutoutD2"), - ("singleRightSlot", "cutoutA3"), - ("singleRightSlot", "cutoutB3"), - ("singleRightSlot", "cutoutC3"), - ("singleRightSlot", "cutoutD3"), + subject.Placement( + cutout_fixture_id=cutout_fixture_id, + cutout_id=cutout_id, + opentrons_module_serial_number=opentrons_module_serial_number, + ) + for cutout_fixture_id, cutout_id, opentrons_module_serial_number in [ + ("singleLeftSlot", "cutoutA1", None), + ("singleLeftSlot", "cutoutB1", None), + ("singleLeftSlot", "cutoutC1", None), + ("singleLeftSlot", "cutoutD1", None), + ("singleCenterSlot", "cutoutA2", None), + ("singleCenterSlot", "cutoutB2", None), + ("singleCenterSlot", "cutoutC2", None), + ("singleCenterSlot", "cutoutD2", None), + ("singleRightSlot", "cutoutA3", None), + ("singleRightSlot", "cutoutB3", None), + ("singleRightSlot", "cutoutC3", None), + ("singleRightSlot", "cutoutD3", None), # Invalid because "someUnrecognizedCutout" is not defined by the deck definition. - ("singleRightSlot", "someUnrecognizedCutout"), + ("singleRightSlot", "someUnrecognizedCutout", None), ] ] assert subject.get_configuration_errors(deck_definition, cutout_fixtures) == { @@ -164,23 +184,27 @@ def test_unrecognized_cutout() -> None: def test_unrecognized_cutout_fixture() -> None: """It should raise a sensible error if you pass a totally nonexistent cutout fixture.""" - deck_definition = load_deck_definition("ot3_standard", version=4) + deck_definition = load_deck_definition("ot3_standard", version=5) cutout_fixtures = [ - subject.Placement(cutout_fixture_id=cutout_fixture_id, cutout_id=cutout_id) - for cutout_fixture_id, cutout_id in [ - ("singleLeftSlot", "cutoutA1"), - ("singleLeftSlot", "cutoutB1"), - ("singleLeftSlot", "cutoutC1"), - ("singleLeftSlot", "cutoutD1"), - ("singleCenterSlot", "cutoutA2"), - ("singleCenterSlot", "cutoutB2"), - ("singleCenterSlot", "cutoutC2"), - ("singleCenterSlot", "cutoutD2"), - ("singleRightSlot", "cutoutA3"), - ("singleRightSlot", "cutoutB3"), - ("singleRightSlot", "cutoutC3"), + subject.Placement( + cutout_fixture_id=cutout_fixture_id, + cutout_id=cutout_id, + opentrons_module_serial_number=opentrons_module_serial_number, + ) + for cutout_fixture_id, cutout_id, opentrons_module_serial_number in [ + ("singleLeftSlot", "cutoutA1", None), + ("singleLeftSlot", "cutoutB1", None), + ("singleLeftSlot", "cutoutC1", None), + ("singleLeftSlot", "cutoutD1", None), + ("singleCenterSlot", "cutoutA2", None), + ("singleCenterSlot", "cutoutB2", None), + ("singleCenterSlot", "cutoutC2", None), + ("singleCenterSlot", "cutoutD2", None), + ("singleRightSlot", "cutoutA3", None), + ("singleRightSlot", "cutoutB3", None), + ("singleRightSlot", "cutoutC3", None), # Invalid because "someUnrecognizedCutoutFixture" is not defined by the deck definition. - ("someUnrecognizedCutoutFixture", "cutoutD3"), + ("someUnrecognizedCutoutFixture", "cutoutD3", None), ] ] assert subject.get_configuration_errors(deck_definition, cutout_fixtures) == { @@ -197,7 +221,115 @@ def test_unrecognized_cutout_fixture() -> None: "stagingAreaSlotWithWasteChuteRightAdapterCovered", "stagingAreaSlotWithWasteChuteRightAdapterNoCover", "trashBinAdapter", + "thermocyclerModuleV2Rear", + "thermocyclerModuleV2Front", + "heaterShakerModuleV1", + "temperatureModuleV2", + "magneticBlockV1", + "stagingAreaSlotWithMagneticBlockV1", ] ), ) } + + +def test_invalid_serial_number() -> None: + """It should raise a sensible error if you fail to provide a serial number for a fixture that requires one.""" + deck_definition = load_deck_definition("ot3_standard", version=5) + cutout_fixtures = [ + subject.Placement( + cutout_fixture_id=cutout_fixture_id, + cutout_id=cutout_id, + opentrons_module_serial_number=opentrons_module_serial_number, + ) + for cutout_fixture_id, cutout_id, opentrons_module_serial_number in [ + ("thermocyclerModuleV2Rear", "cutoutA1", "ABC"), + # Invalid, because the Thermocycler V2 Front fixture requires a serial number + ("thermocyclerModuleV2Front", "cutoutB1", None), + ("singleLeftSlot", "cutoutC1", None), + ("singleLeftSlot", "cutoutD1", None), + ("singleCenterSlot", "cutoutA2", None), + ("singleCenterSlot", "cutoutB2", None), + ("singleCenterSlot", "cutoutC2", None), + ("singleCenterSlot", "cutoutD2", None), + ("singleRightSlot", "cutoutA3", None), + ("singleRightSlot", "cutoutB3", None), + ("singleRightSlot", "cutoutC3", None), + ("singleRightSlot", "cutoutD3", None), + ] + ] + assert subject.get_configuration_errors(deck_definition, cutout_fixtures) == { + subject.InvalidSerialNumberError( + cutout_fixture_id="thermocyclerModuleV2Front", + cutout_id="cutoutB1", + ) + } + + +def test_unexpected_serial_number() -> None: + """It should raise a sensible error if you provide a serial number for a fixture that DOES NOT require one.""" + deck_definition = load_deck_definition("ot3_standard", version=5) + cutout_fixtures = [ + subject.Placement( + cutout_fixture_id=cutout_fixture_id, + cutout_id=cutout_id, + opentrons_module_serial_number=opentrons_module_serial_number, + ) + for cutout_fixture_id, cutout_id, opentrons_module_serial_number in [ + # Invalid, single slot fixtures do not have serial numbers + ("singleLeftSlot", "cutoutA1", "ABC"), + ("singleLeftSlot", "cutoutB1", None), + ("singleLeftSlot", "cutoutC1", None), + ("singleLeftSlot", "cutoutD1", None), + ("singleCenterSlot", "cutoutA2", None), + ("singleCenterSlot", "cutoutB2", None), + ("singleCenterSlot", "cutoutC2", None), + ("singleCenterSlot", "cutoutD2", None), + ("singleRightSlot", "cutoutA3", None), + ("singleRightSlot", "cutoutB3", None), + ("singleRightSlot", "cutoutC3", None), + ("singleRightSlot", "cutoutD3", None), + ] + ] + assert subject.get_configuration_errors(deck_definition, cutout_fixtures) == { + subject.UnexpectedSerialNumberError( + cutout_fixture_id="singleLeftSlot", + cutout_id="cutoutA1", + opentrons_module_serial_number="ABC", + ) + } + + +# new test to raise error if not all members of a fixture group are loaded into the deck config +def test_missing_group_fixture() -> None: + """It should raise a sensible error if you fail to provide all members of a fixture group in a deck configuration.""" + deck_definition = load_deck_definition("ot3_standard", version=5) + cutout_fixtures = [ + subject.Placement( + cutout_fixture_id=cutout_fixture_id, + cutout_id=cutout_id, + opentrons_module_serial_number=opentrons_module_serial_number, + ) + for cutout_fixture_id, cutout_id, opentrons_module_serial_number in [ + ("thermocyclerModuleV2Rear", "cutoutA1", "ABC"), + # Invalid, because the Thermocycler V2 Rear fixture above requires a Front fixture be loaded as well + ("singleLeftSlot", "cutoutB1", None), + ("singleLeftSlot", "cutoutC1", None), + ("singleLeftSlot", "cutoutD1", None), + ("singleCenterSlot", "cutoutA2", None), + ("singleCenterSlot", "cutoutB2", None), + ("singleCenterSlot", "cutoutC2", None), + ("singleCenterSlot", "cutoutD2", None), + ("singleRightSlot", "cutoutA3", None), + ("singleRightSlot", "cutoutB3", None), + ("singleRightSlot", "cutoutC3", None), + ("singleRightSlot", "cutoutD3", None), + ] + ] + assert subject.get_configuration_errors(deck_definition, cutout_fixtures) == { + subject.MissingGroupFixtureError( + cutout_fixture_id="thermocyclerModuleV2Rear", + cutout_id="cutoutA1", + missing_fixture_id="thermocyclerModuleV2Front", + ) + } diff --git a/robot-server/tests/integration/conftest.py b/robot-server/tests/integration/conftest.py index 7e42a836a71..2c8d66853a1 100644 --- a/robot-server/tests/integration/conftest.py +++ b/robot-server/tests/integration/conftest.py @@ -40,21 +40,6 @@ def pytest_tavern_beta_after_every_response( print(json.dumps(response.json(), indent=4)) -@pytest.fixture -def ot2_server_set_disable_fast_analysis( - ot2_server_base_url: str, -) -> Generator[None, None, None]: - """For integration tests that need to set then clear the - disableFastProtocolUpload feature flag""" - url = f"{ot2_server_base_url}/settings" - data = {"id": "disableFastProtocolUpload", "value": True} - with _requests_session() as requests_session: - requests_session.post(url, json=data) - yield None - data["value"] = None - requests.post(url, json=data) - - @pytest.fixture def ot2_server_base_url(_ot2_session_server: str) -> Generator[str, None, None]: """Return the URL for a running dev server. diff --git a/robot-server/tests/integration/http_api/commands/test_load_module_success.tavern.yaml b/robot-server/tests/integration/http_api/commands/test_load_module_success.tavern.yaml index 8e4e99528a7..c9cc22f8e0d 100644 --- a/robot-server/tests/integration/http_api/commands/test_load_module_success.tavern.yaml +++ b/robot-server/tests/integration/http_api/commands/test_load_module_success.tavern.yaml @@ -49,7 +49,7 @@ stages: params: model: '{model}' location: - slotName: '10' + slotName: '7' response: strict: - json:off diff --git a/robot-server/tests/integration/http_api/protocols/test_upload.tavern.yaml b/robot-server/tests/integration/http_api/protocols/test_upload.tavern.yaml index 63bf756bc8d..c7b16d64d47 100644 --- a/robot-server/tests/integration/http_api/protocols/test_upload.tavern.yaml +++ b/robot-server/tests/integration/http_api/protocols/test_upload.tavern.yaml @@ -92,41 +92,3 @@ stages: errors: - id: ProtocolNotFound title: Protocol Not Found - ---- -test_name: Upload, analyze and analyze using "slow analysis" - -marks: - - usefixtures: - - ot2_server_base_url - - ot2_server_set_disable_fast_analysis - -stages: - - name: Upload simple Python protocol - request: - url: '{ot2_server_base_url}/protocols' - method: POST - files: - files: 'tests/integration/protocols/simple.py' - response: - save: - json: - protocol_id: data.id - analysis_id: data.analysisSummaries[0].id - status_code: 201 - - - name: Retry until analyses status is completed and result is ok. - max_retries: 10 - delay_after: 0.1 - request: - url: '{ot2_server_base_url}/protocols/{protocol_id}/analyses' - method: GET - response: - strict: - - json:off - status_code: 200 - json: - data: - - id: '{analysis_id}' - status: completed - result: ok diff --git a/robot-server/tests/integration/http_api/protocols/test_v8_json_upload_flex.tavern.yaml b/robot-server/tests/integration/http_api/protocols/test_v8_json_upload_flex.tavern.yaml index 991d88df87f..af2fc892b86 100644 --- a/robot-server/tests/integration/http_api/protocols/test_v8_json_upload_flex.tavern.yaml +++ b/robot-server/tests/integration/http_api/protocols/test_v8_json_upload_flex.tavern.yaml @@ -103,7 +103,7 @@ stages: definitionUri: opentrons/armadillo_96_wellplate_200ul_pcr_full_skirt/1 displayName: Sample Collection Plate location: - moduleId: magneticModuleId + moduleId: magneticBlockId - id: tipRackId loadName: opentrons_96_tiprack_1000ul definitionUri: opentrons/opentrons_96_tiprack_1000ul/1 @@ -117,9 +117,8 @@ stages: location: slotName: 'A3' modules: - - id: magneticModuleId - serialNumber: !anystr - model: magneticModuleV2 + - id: magneticBlockId + model: magneticBlockV1 location: slotName: 'D3' - id: temperatureModuleId @@ -159,15 +158,14 @@ stages: key: !anystr status: succeeded params: - model: magneticModuleV2 + model: magneticBlockV1 location: slotName: 'D3' - moduleId: magneticModuleId + moduleId: magneticBlockId result: - moduleId: magneticModuleId + moduleId: magneticBlockId definition: !anydict - model: magneticModuleV2 - serialNumber: !anystr + model: magneticBlockV1 notes: [] startedAt: !anystr completedAt: !anystr @@ -215,7 +213,7 @@ stages: status: succeeded params: location: - moduleId: magneticModuleId + moduleId: magneticBlockId loadName: armadillo_96_wellplate_200ul_pcr_full_skirt namespace: opentrons version: 1 @@ -365,7 +363,7 @@ stages: volume: 4.5 flowRate: 2.5 result: - position: { 'x': 341.205, 'y': 65.115, 'z': 84.3 } + position: { 'x': 342.38, 'y': 65.24, 'z': 40.05 } volume: 4.5 notes: [] startedAt: !anystr @@ -388,7 +386,7 @@ stages: radius: 1.0 speed: 42.0 result: - position: { 'x': 341.205, 'y': 65.115, 'z': 94.3 } + position: { 'x': 342.38, 'y': 65.24, 'z': 50.05 } notes: [] startedAt: !anystr completedAt: !anystr @@ -409,7 +407,7 @@ stages: z: 12.0 flowRate: 2.0 result: - position: { 'x': 341.205, 'y': 65.115, 'z': 95.3 } + position: { 'x': 342.38, 'y': 65.24, 'z': 51.05 } notes: [] startedAt: !anystr completedAt: !anystr @@ -448,7 +446,8 @@ stages: forceDirect: false speed: 12.3 result: - position: { 'x': 350.205, 'y': 65.115, 'z': 98.25 } + position: + { 'x': 351.38, 'y': 65.24, 'z': 54.0 } notes: [] startedAt: !anystr completedAt: !anystr @@ -470,7 +469,8 @@ stages: minimumZHeight: 35.0 forceDirect: true result: - position: { 'x': 352.205, 'y': 68.115, 'z': 93.3 } + position: + { 'x': 353.38, 'y': 68.24, 'z': 49.05 } notes: [] startedAt: !anystr completedAt: !anystr diff --git a/robot-server/tests/integration/http_api/runs/test_deck_slot_standardization.py b/robot-server/tests/integration/http_api/runs/test_deck_slot_standardization.py index aa39376cafe..4f065b9a59c 100644 --- a/robot-server/tests/integration/http_api/runs/test_deck_slot_standardization.py +++ b/robot-server/tests/integration/http_api/runs/test_deck_slot_standardization.py @@ -4,6 +4,7 @@ from pytest_lazyfixture import lazy_fixture # type: ignore[import-untyped] from ...robot_client import RobotClient +from ...conftest import _OT3_SESSION_SERVER_PORT @pytest.fixture @@ -58,6 +59,29 @@ async def test_deck_slot_standardization( """ module_model = "temperatureModuleV2" + deck_configuration_request = [ + {"cutoutFixtureId": "singleLeftSlot", "cutoutId": "cutoutA1"}, + {"cutoutFixtureId": "singleLeftSlot", "cutoutId": "cutoutB1"}, + {"cutoutFixtureId": "singleLeftSlot", "cutoutId": "cutoutC1"}, + { + "cutoutFixtureId": "temperatureModuleV2", + "cutoutId": "cutoutD1", + "opentronsModuleSerialNumber": "temp-1234", + }, + {"cutoutFixtureId": "singleCenterSlot", "cutoutId": "cutoutA2"}, + {"cutoutFixtureId": "singleCenterSlot", "cutoutId": "cutoutB2"}, + {"cutoutFixtureId": "singleCenterSlot", "cutoutId": "cutoutC2"}, + {"cutoutFixtureId": "singleCenterSlot", "cutoutId": "cutoutD2"}, + {"cutoutFixtureId": "singleRightSlot", "cutoutId": "cutoutA3"}, + {"cutoutFixtureId": "singleRightSlot", "cutoutId": "cutoutB3"}, + {"cutoutFixtureId": "singleRightSlot", "cutoutId": "cutoutC3"}, + {"cutoutFixtureId": "singleRightSlot", "cutoutId": "cutoutD3"}, + ] + if _OT3_SESSION_SERVER_PORT in robot_client.base_url: + await robot_client.put_deck_configuration( + req_body={"data": {"cutoutFixtures": deck_configuration_request}} + ) + labware_load_name = "armadillo_96_wellplate_200ul_pcr_full_skirt" labware_namespace = "opentrons" labware_version = 1 diff --git a/robot-server/tests/integration/http_api/runs/test_json_v6_protocol_run.tavern.yaml b/robot-server/tests/integration/http_api/runs/test_json_v6_protocol_run.tavern.yaml index 4ff631bf277..e7ac3483dd7 100644 --- a/robot-server/tests/integration/http_api/runs/test_json_v6_protocol_run.tavern.yaml +++ b/robot-server/tests/integration/http_api/runs/test_json_v6_protocol_run.tavern.yaml @@ -50,6 +50,7 @@ stages: displayName: Water description: Liquid H2O displayColor: '#7332a8' + runTimeParameters: [] protocolId: '{protocol_id}' - name: Execute a setup command diff --git a/robot-server/tests/integration/http_api/runs/test_json_v7_protocol_run.tavern.yaml b/robot-server/tests/integration/http_api/runs/test_json_v7_protocol_run.tavern.yaml index 317d339fbbf..bdc4ad4a66d 100644 --- a/robot-server/tests/integration/http_api/runs/test_json_v7_protocol_run.tavern.yaml +++ b/robot-server/tests/integration/http_api/runs/test_json_v7_protocol_run.tavern.yaml @@ -45,6 +45,7 @@ stages: definitionUri: opentrons/opentrons_1_trash_1100ml_fixed/1 location: !anydict labwareOffsets: [] + runTimeParameters: [] liquids: - id: waterId displayName: Water diff --git a/robot-server/tests/integration/http_api/runs/test_persistence.py b/robot-server/tests/integration/http_api/runs/test_persistence.py index 45b55202fda..943f644e8d3 100644 --- a/robot-server/tests/integration/http_api/runs/test_persistence.py +++ b/robot-server/tests/integration/http_api/runs/test_persistence.py @@ -1,3 +1,4 @@ +import json from copy import deepcopy from datetime import datetime from typing import Any, AsyncGenerator, Dict, NamedTuple, cast @@ -250,6 +251,9 @@ async def test_run_commands_persist(client_and_server: ClientServerFixture) -> N get_persisted_command_response = await client.get_run_command( run_id=run_id, command_id=command_id ) + get_preserialized_commands_response = await client.get_preserialized_commands( + run_id=run_id + ) # ensure the persisted commands still match the original ones assert get_all_persisted_commands_response.json()["data"] == [ @@ -259,6 +263,11 @@ async def test_run_commands_persist(client_and_server: ClientServerFixture) -> N ] assert get_persisted_command_response.json()["data"] == expected_command + json_converted_command = json.loads( + get_preserialized_commands_response.json()["data"][0] + ) + assert json_converted_command == expected_command + async def test_runs_completed_started_at_persist_via_actions_router( client_and_server: ClientServerFixture, diff --git a/robot-server/tests/integration/http_api/runs/test_protocol_run.tavern.yaml b/robot-server/tests/integration/http_api/runs/test_protocol_run.tavern.yaml index 48dc570d6c9..67d1511a666 100644 --- a/robot-server/tests/integration/http_api/runs/test_protocol_run.tavern.yaml +++ b/robot-server/tests/integration/http_api/runs/test_protocol_run.tavern.yaml @@ -42,6 +42,7 @@ stages: definitionUri: opentrons/opentrons_1_trash_1100ml_fixed/1 location: !anydict labwareOffsets: [] + runTimeParameters: [] protocolId: '{protocol_id}' liquids: [] save: @@ -237,6 +238,7 @@ stages: createdAt: !re_search "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d+\\+\\d{2}:\\d{2}$" startedAt: !re_search "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d+\\+\\d{2}:\\d{2}$" liquids: [] + runTimeParameters: [] completedAt: !re_search "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d+\\+\\d{2}:\\d{2}$" errors: [] pipettes: [] diff --git a/robot-server/tests/integration/http_api/runs/test_run_queued_protocol_commands.tavern.yaml b/robot-server/tests/integration/http_api/runs/test_run_queued_protocol_commands.tavern.yaml index cc8cea69356..9d188402deb 100644 --- a/robot-server/tests/integration/http_api/runs/test_run_queued_protocol_commands.tavern.yaml +++ b/robot-server/tests/integration/http_api/runs/test_run_queued_protocol_commands.tavern.yaml @@ -94,6 +94,7 @@ stages: labware: [] labwareOffsets: [] liquids: [] + runTimeParameters: [] modules: [] pipettes: [] status: 'idle' @@ -197,3 +198,19 @@ stages: createdAt: !re_search "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d+\\+\\d{2}:\\d{2}$" startedAt: !re_search "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d+\\+\\d{2}:\\d{2}$" completedAt: !re_search "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d+\\+\\d{2}:\\d{2}$" + + - name: Get all the commands in the run as a pre-serialized list + request: + url: '{ot2_server_base_url}/runs/{run_id}/commandsAsPreSerializedList' + method: GET + response: + status_code: 200 + json: + data: + - !anystr + - !anystr + - !anystr + - !anystr + meta: + cursor: 0 + totalLength: 4 \ No newline at end of file diff --git a/robot-server/tests/integration/http_api/runs/test_run_with_run_time_parameters.tavern.yaml b/robot-server/tests/integration/http_api/runs/test_run_with_run_time_parameters.tavern.yaml new file mode 100644 index 00000000000..d7f075b18cb --- /dev/null +++ b/robot-server/tests/integration/http_api/runs/test_run_with_run_time_parameters.tavern.yaml @@ -0,0 +1,203 @@ +test_name: Test the run endpoints with run time parameters + +marks: + - usefixtures: + - ot2_server_base_url + +stages: + - name: Upload a protocol + request: + url: '{ot2_server_base_url}/protocols' + method: POST + files: + files: 'tests/integration/protocols/basic_transfer_with_run_time_parameters.py' + response: + status_code: 201 + save: + json: + protocol_id: data.id + + - name: Create run from protocol + request: + url: '{ot2_server_base_url}/runs' + method: POST + json: + data: + protocolId: '{protocol_id}' + runTimeParameterValues: + sample_count: 4 + volume: 10.23 + dry_run: True + pipette: flex_8channel_50 + response: + status_code: 201 + save: + json: + run_id: data.id + json: + data: + id: !anystr + ok: True + createdAt: !anystr + status: idle + current: True + actions: [] + errors: [] + pipettes: [] + modules: [] + labware: [] + labwareOffsets: [] + runTimeParameters: [] + liquids: [] + protocolId: '{protocol_id}' + + - name: Play the run + request: + url: '{ot2_server_base_url}/runs/{run_id}/actions' + method: POST + json: + data: + actionType: play + response: + status_code: 201 + json: + data: + id: !anystr + actionType: play + createdAt: !anystr + + - name: Wait for the protocol to complete + max_retries: 10 + delay_after: 0.1 + request: + url: '{ot2_server_base_url}/runs/{run_id}' + method: GET + response: + status_code: 200 + strict: + - json:off + json: + data: + status: succeeded + + - name: Verify the run contains the set run time parameters + request: + url: '{ot2_server_base_url}/runs/{run_id}' + method: GET + response: + status_code: 200 + strict: + - json:off + json: + data: + id: !anystr + ok: True + createdAt: !anystr + status: succeeded + current: True + runTimeParameters: + - displayName: Sample count + variableName: sample_count + type: int + default: 6.0 + min: 1.0 + max: 12.0 + value: 4.0 + description: How many samples to process. + - displayName: Pipette volume + variableName: volume + type: float + default: 20.1 + choices: + - displayName: Low Volume + value: 10.23 + - displayName: Medium Volume + value: 20.1 + - displayName: High Volume + value: 50.5 + value: 10.23 + description: How many microliters to pipette of each sample. + - displayName: Dry Run + variableName: dry_run + type: bool + default: false + value: true + description: Skip aspirate and dispense steps. + - displayName: Pipette Name + variableName: pipette + type: str + choices: + - displayName: Single channel 50µL + value: flex_1channel_50 + - displayName: Eight Channel 50µL + value: flex_8channel_50 + default: flex_1channel_50 + value: flex_8channel_50 + description: What pipette to use during the protocol. + protocolId: '{protocol_id}' + + - name: Mark the run as not-current + request: + url: '{ot2_server_base_url}/runs/{run_id}' + method: PATCH + json: + data: + current: False + response: + status_code: 200 + + - name: Verify the archived run still contains the set run time parameters + request: + url: '{ot2_server_base_url}/runs/{run_id}' + method: GET + response: + status_code: 200 + strict: + - json:off + json: + data: + id: !anystr + ok: True + createdAt: !anystr + status: succeeded + current: False + runTimeParameters: + - displayName: Sample count + variableName: sample_count + type: int + default: 6.0 + min: 1.0 + max: 12.0 + value: 4.0 + description: How many samples to process. + - displayName: Pipette volume + variableName: volume + type: float + default: 20.1 + choices: + - displayName: Low Volume + value: 10.23 + - displayName: Medium Volume + value: 20.1 + - displayName: High Volume + value: 50.5 + value: 10.23 + description: How many microliters to pipette of each sample. + - displayName: Dry Run + variableName: dry_run + type: bool + default: false + value: true + description: Skip aspirate and dispense steps. + - displayName: Pipette Name + variableName: pipette + type: str + choices: + - displayName: Single channel 50µL + value: flex_1channel_50 + - displayName: Eight Channel 50µL + value: flex_8channel_50 + default: flex_1channel_50 + value: flex_8channel_50 + description: What pipette to use during the protocol. + protocolId: '{protocol_id}' diff --git a/robot-server/tests/integration/http_api/test_command_key_hash_matching.tavern.yaml b/robot-server/tests/integration/http_api/test_command_key_hash_matching.tavern.yaml new file mode 100644 index 00000000000..db2c4ddceda --- /dev/null +++ b/robot-server/tests/integration/http_api/test_command_key_hash_matching.tavern.yaml @@ -0,0 +1,119 @@ +test_name: Test that command keys in analysis and protocol run match for a deterministic protocol running using protocol engine + +marks: + - usefixtures: + - ot2_server_base_url + +stages: + - name: Upload a protocol + request: + url: '{ot2_server_base_url}/protocols' + method: POST + files: + files: 'tests/integration/protocols/basic_transfer_with_run_time_parameters.py' + response: + save: + json: + protocol_id: data.id + analysis_id: data.analysisSummaries[0].id + strict: + - json:off + status_code: 201 + + - name: Save command keys from protocol analysis + max_retries: 5 + delay_after: 1 + request: + url: '{ot2_server_base_url}/protocols/{protocol_id}/analyses/{analysis_id}' + response: + save: + json: + analysis_data: data + home_cmd_key: data.commands[0].key + plate_load_key: data.commands[1].key + pipette_load_key: data.commands[3].key + pick_up_tip_key: data.commands[4].key + drop_tip_key: data.commands[7].key + strict: + - json:off + json: + data: + id: '{analysis_id}' + commands: + - commandType: loadPipette + + - name: Create run from protocol + request: + url: '{ot2_server_base_url}/runs' + method: POST + json: + data: + protocolId: '{protocol_id}' + response: + status_code: 201 + save: + json: + original_run_data: data + run_id: data.id + + - name: Play the run + request: + url: '{ot2_server_base_url}/runs/{run_id}/actions' + method: POST + json: + data: + actionType: play + response: + status_code: 201 + + - name: Wait for the protocol to complete + max_retries: 5 + delay_after: 1 + request: + url: '{ot2_server_base_url}/runs/{run_id}' + method: GET + response: + status_code: 200 + strict: + - json:off + json: + data: + status: succeeded + + - name: Verify commands have keys identical to their counterparts in analysis + request: + url: '{ot2_server_base_url}/runs/{run_id}/commands' + method: GET + response: + strict: + - json:off + status_code: 200 + json: + links: + current: + href: !anystr + meta: + runId: !anystr + commandId: !anystr + index: 7 + key: !anystr + createdAt: !anystr + meta: + cursor: 0 + totalLength: 8 + data: + - id: !anystr + key: '{home_cmd_key}' + commandType: home + - id: !anystr + key: '{plate_load_key}' + commandType: loadLabware + - id: !anystr + key: '{pipette_load_key}' + commandType: loadPipette + - id: !anystr + key: '{pick_up_tip_key}' + commandType: pickUpTip + - id: !anystr + key: '{drop_tip_key}' + commandType: dropTip diff --git a/robot-server/tests/integration/robot_client.py b/robot-server/tests/integration/robot_client.py index 90869cdde92..9af11d50cdb 100644 --- a/robot-server/tests/integration/robot_client.py +++ b/robot-server/tests/integration/robot_client.py @@ -220,6 +220,14 @@ async def get_run_command(self, run_id: str, command_id: str) -> Response: response.raise_for_status() return response + async def get_preserialized_commands(self, run_id: str) -> Response: + """GET /runs/:run_id/commandsAsPreSerializedList.""" + response = await self.httpx_client.get( + url=f"{self.base_url}/runs/{run_id}/commandsAsPreSerializedList", + ) + response.raise_for_status() + return response + async def post_labware_offset( self, run_id: str, @@ -312,6 +320,18 @@ async def delete_session(self, session_id: str) -> Response: response.raise_for_status() return response + async def put_deck_configuration( + self, + req_body: Dict[str, object], + ) -> Response: + """PUT /deck_configuration.""" + response = await self.httpx_client.put( + url=f"{self.base_url}/deck_configuration", + json=req_body, + ) + response.raise_for_status() + return response + async def poll_until_run_completes( robot_client: RobotClient, run_id: str, poll_interval: float = _RUN_POLL_INTERVAL diff --git a/robot-server/tests/integration/test_settings.tavern.yaml b/robot-server/tests/integration/test_settings.tavern.yaml index 754a74f5a04..5ea380778c5 100644 --- a/robot-server/tests/integration/test_settings.tavern.yaml +++ b/robot-server/tests/integration/test_settings.tavern.yaml @@ -42,12 +42,6 @@ stages: description: !re_search 'Automatically pause protocols when robot door opens' restart_required: false value: !anything - - id: disableFastProtocolUpload - old_id: Null - title: Use older protocol analysis method - description: !re_search 'Use an older, slower method of analyzing uploaded protocols' - restart_required: false - value: !anything links: !anydict --- @@ -64,7 +58,6 @@ marks: - disableHomeOnBoot - useOldAspirationFunctions - enableDoorSafetySwitch - - disableFastProtocolUpload - parametrize: key: value vals: @@ -100,7 +93,6 @@ marks: - disableHomeOnBoot - useOldAspirationFunctions - enableDoorSafetySwitch - - disableFastProtocolUpload stages: - name: Set each setting to acceptable values request: diff --git a/robot-server/tests/maintenance_runs/test_engine_store.py b/robot-server/tests/maintenance_runs/test_engine_store.py index 15855ab48d1..948705572ce 100644 --- a/robot-server/tests/maintenance_runs/test_engine_store.py +++ b/robot-server/tests/maintenance_runs/test_engine_store.py @@ -6,6 +6,7 @@ from opentrons_shared_data.robot.dev_types import RobotType +from opentrons.protocol_engine.errors.exceptions import EStopActivatedError from opentrons.types import DeckSlotName from opentrons.hardware_control import API from opentrons.hardware_control.types import EstopStateNotification, EstopState @@ -20,7 +21,7 @@ MaintenanceEngineStore, EngineConflictError, NoRunnerEnginePairError, - get_estop_listener, + handle_estop_event, ) @@ -30,7 +31,7 @@ def mock_notify_publishers() -> None: @pytest.fixture -def subject(decoy: Decoy) -> MaintenanceEngineStore: +async def subject(decoy: Decoy) -> MaintenanceEngineStore: """Get a MaintenanceEngineStore test subject.""" # TODO(mc, 2021-06-11): to make these test more effective and valuable, we # should pass in some sort of actual, valid HardwareAPI instead of a mock @@ -176,22 +177,30 @@ async def test_estop_callback( """The callback should stop an active engine.""" engine_store = decoy.mock(cls=MaintenanceEngineStore) - subject = get_estop_listener(engine_store=engine_store) - - decoy.when(engine_store.current_run_id).then_return(None, "fake_run_id") - disengage_event = EstopStateNotification( old_state=EstopState.PHYSICALLY_ENGAGED, new_state=EstopState.LOGICALLY_ENGAGED ) - - subject(disengage_event) - engage_event = EstopStateNotification( old_state=EstopState.LOGICALLY_ENGAGED, new_state=EstopState.PHYSICALLY_ENGAGED ) - subject(engage_event) - - subject(engage_event) + decoy.when(engine_store.current_run_id).then_return(None) + await handle_estop_event(engine_store, disengage_event) + decoy.verify( + engine_store.engine.estop(), + ignore_extra_args=True, + times=0, + ) + decoy.verify( + await engine_store.engine.finish(), + ignore_extra_args=True, + times=0, + ) - decoy.verify(engine_store.engine.estop(maintenance_run=True), times=1) + decoy.when(engine_store.current_run_id).then_return("fake-run-id") + await handle_estop_event(engine_store, engage_event) + decoy.verify( + engine_store.engine.estop(), + await engine_store.engine.finish(error=matchers.IsA(EStopActivatedError)), + times=1, + ) diff --git a/robot-server/tests/persistence/test_tables.py b/robot-server/tests/persistence/test_tables.py index eaa2824ce75..5f3c45adcaa 100644 --- a/robot-server/tests/persistence/test_tables.py +++ b/robot-server/tests/persistence/test_tables.py @@ -56,6 +56,7 @@ state_summary VARCHAR, engine_status VARCHAR, _updated_at DATETIME, + run_time_parameters VARCHAR, PRIMARY KEY (id), FOREIGN KEY(protocol_id) REFERENCES protocol (id) ) diff --git a/robot-server/tests/protocols/test_analysis_store.py b/robot-server/tests/protocols/test_analysis_store.py index 94d7f67f953..090cb680dfe 100644 --- a/robot-server/tests/protocols/test_analysis_store.py +++ b/robot-server/tests/protocols/test_analysis_store.py @@ -319,7 +319,7 @@ async def test_update_adds_rtp_values_and_defaults_to_completed_store( liquids=[], ) decoy.verify( - await mock_completed_store.add( + await mock_completed_store.make_room_and_add( completed_analysis_resource=expected_completed_analysis_resource ) ) diff --git a/robot-server/tests/protocols/test_completed_analysis_store.py b/robot-server/tests/protocols/test_completed_analysis_store.py index f41594d0c5d..1cac25fb4e1 100644 --- a/robot-server/tests/protocols/test_completed_analysis_store.py +++ b/robot-server/tests/protocols/test_completed_analysis_store.py @@ -2,12 +2,13 @@ import json from datetime import datetime, timezone from pathlib import Path -from typing import Optional, Dict +from typing import Optional, Dict, List import pytest from sqlalchemy.engine import Engine from decoy import Decoy +from robot_server.persistence.tables import analysis_table from robot_server.protocols.completed_analysis_store import ( CompletedAnalysisResource, CompletedAnalysisStore, @@ -125,7 +126,7 @@ async def test_get_by_analysis_id_falls_back_to_sql( """It should return analyses from sql if they are not cached.""" resource = _completed_analysis_resource("analysis-id", "protocol-id") protocol_store.insert(make_dummy_protocol_resource("protocol-id")) - await subject.add(resource) + await subject.make_room_and_add(resource) # the analysis is not cached decoy.when(memcache.get("analysis-id")).then_raise(KeyError()) analysis_from_sql = await subject.get_by_id("analysis-id") @@ -142,7 +143,7 @@ async def test_get_by_analysis_id_stores_results_in_cache( """It should cache successful fetches from sql.""" resource = _completed_analysis_resource("analysis-id", "protocol-id") protocol_store.insert(make_dummy_protocol_resource("protocol-id")) - await subject.add(resource) + await subject.make_room_and_add(resource) # the analysis is not cached decoy.when(memcache.get("analysis-id")).then_raise(KeyError()) from_sql = await subject.get_by_id("analysis-id") @@ -157,7 +158,7 @@ async def test_get_by_analysis_id_as_document( """It should return the analysis serialized as a JSON string.""" resource = _completed_analysis_resource("analysis-id", "protocol-id") protocol_store.insert(make_dummy_protocol_resource("protocol-id")) - await subject.add(resource) + await subject.make_room_and_add(resource) result = await subject.get_by_id_as_document("analysis-id") assert result is not None assert json.loads(result) == { @@ -183,9 +184,9 @@ async def test_get_ids_by_protocol( resource_3 = _completed_analysis_resource("analysis-id-3", "protocol-id-2") protocol_store.insert(make_dummy_protocol_resource("protocol-id-1")) protocol_store.insert(make_dummy_protocol_resource("protocol-id-2")) - await subject.add(resource_1) - await subject.add(resource_2) - await subject.add(resource_3) + await subject.make_room_and_add(resource_1) + await subject.make_room_and_add(resource_2) + await subject.make_room_and_add(resource_3) assert subject.get_ids_by_protocol("protocol-id-1") == [ "analysis-id-1", "analysis-id-2", @@ -207,9 +208,9 @@ async def test_get_by_protocol( decoy.when(memcache.insert("analysis-id-1", resource_1)).then_return(None) decoy.when(memcache.insert("analysis-id-2", resource_2)).then_return(None) decoy.when(memcache.insert("analysis-id-3", resource_3)).then_return(None) - await subject.add(resource_1) - await subject.add(resource_2) - await subject.add(resource_3) + await subject.make_room_and_add(resource_1) + await subject.make_room_and_add(resource_2) + await subject.make_room_and_add(resource_3) decoy.when(memcache.get("analysis-id-1")).then_raise(KeyError()) decoy.when(memcache.get("analysis-id-2")).then_return(resource_2) decoy.when(memcache.contains("analysis-id-1")).then_return(False) @@ -256,8 +257,104 @@ async def test_get_rtp_values_and_defaults_by_analysis_from_db( }, ) protocol_store.insert(make_dummy_protocol_resource("protocol-id")) - await subject.add(resource) + await subject.make_room_and_add(resource) # Not in memcache decoy.when(memcache.get("analysis-id")).then_raise(KeyError()) result = await subject.get_rtp_values_and_defaults_by_analysis_id("analysis-id") assert result == resource.run_time_parameter_values_and_defaults + + +@pytest.mark.parametrize( + argnames=["existing_analysis_ids", "expected_analyses_ids_after_making_room"], + argvalues=[ + ( + [f"analysis-id-{num}" for num in range(8)], + [ + "analysis-id-4", + "analysis-id-5", + "analysis-id-6", + "analysis-id-7", + "new-analysis-id", + ], + ), + ( + [f"analysis-id-{num}" for num in range(5)], + [ + "analysis-id-1", + "analysis-id-2", + "analysis-id-3", + "analysis-id-4", + "new-analysis-id", + ], + ), + ( + [f"analysis-id-{num}" for num in range(4)], + [ + "analysis-id-0", + "analysis-id-1", + "analysis-id-2", + "analysis-id-3", + "new-analysis-id", + ], + ), + ( + [f"analysis-id-{num}" for num in range(3)], + [ + "analysis-id-0", + "analysis-id-1", + "analysis-id-2", + "new-analysis-id", + ], + ), + ( + [f"analysis-id-{num}" for num in range(2)], + ["analysis-id-0", "analysis-id-1", "new-analysis-id"], + ), + (["analysis-id-0"], ["analysis-id-0", "new-analysis-id"]), + ([], ["new-analysis-id"]), + ], +) +async def test_add_makes_room_for_new_analysis( + subject: CompletedAnalysisStore, + memcache: MemoryCache[str, CompletedAnalysisResource], + protocol_store: ProtocolStore, + existing_analysis_ids: List[str], + expected_analyses_ids_after_making_room: List[str], + decoy: Decoy, + sql_engine: Engine, +) -> None: + """It should delete old analyses and make room for new analysis.""" + protocol_store.insert(make_dummy_protocol_resource("protocol-id")) + + # Set up the database with existing analyses + resources = [ + _completed_analysis_resource( + analysis_id=analysis_id, + protocol_id="protocol-id", + ) + for analysis_id in existing_analysis_ids + ] + for resource in resources: + statement = analysis_table.insert().values(await resource.to_sql_values()) + with sql_engine.begin() as transaction: + transaction.execute(statement) + + assert subject.get_ids_by_protocol("protocol-id") == existing_analysis_ids + await subject.make_room_and_add( + _completed_analysis_resource( + analysis_id="new-analysis-id", + protocol_id="protocol-id", + ) + ) + assert ( + subject.get_ids_by_protocol("protocol-id") + == expected_analyses_ids_after_making_room + ) + + removed_ids = [ + analysis_id + for analysis_id in existing_analysis_ids + if analysis_id not in expected_analyses_ids_after_making_room + ] + for analysis_id in removed_ids: + decoy.verify(memcache.remove(analysis_id)) diff --git a/robot-server/tests/protocols/test_memcache.py b/robot-server/tests/protocols/test_memcache.py index ce485d8984f..80acb184f20 100644 --- a/robot-server/tests/protocols/test_memcache.py +++ b/robot-server/tests/protocols/test_memcache.py @@ -22,3 +22,19 @@ def test_cache_retains_new_values() -> None: for val in range(1, 4): assert subject.contains(f"key-{val}") assert subject.get(f"key-{val}") == f"value-{val}" + + +def test_cache_removes_values_by_key() -> None: + """It should eject values when asked for it.""" + subject = MemoryCache(3, str, str) + for val in range(3): + subject.insert(f"key-{val}", f"value-{val}") + subject.remove("key-1") + assert not subject.contains("key-1") + + # Make sure cache order is updated + assert subject.contains("key-0") and subject.contains("key-2") + subject.insert("key-4", "value-4") + assert subject.contains("key-0") + subject.insert("key-5", "value-5") + assert not subject.contains("key-0") diff --git a/robot-server/tests/runs/router/test_commands_router.py b/robot-server/tests/runs/router/test_commands_router.py index fa5e47ada9a..93adb46fa53 100644 --- a/robot-server/tests/runs/router/test_commands_router.py +++ b/robot-server/tests/runs/router/test_commands_router.py @@ -114,10 +114,11 @@ def _stub_queued_command_state(*_a: object, **_k: object) -> pe_commands.Command decoy.when( mock_protocol_engine.add_command( - pe_commands.WaitForResumeCreate( + request=pe_commands.WaitForResumeCreate( params=pe_commands.WaitForResumeParams(message="Hello"), intent=pe_commands.CommandIntent.SETUP, - ) + ), + failed_command_id=None, ) ).then_do(_stub_queued_command_state) @@ -125,6 +126,7 @@ def _stub_queued_command_state(*_a: object, **_k: object) -> pe_commands.Command request_body=RequestModelWithCommandCreate(data=command_request), waitUntilComplete=False, protocol_engine=mock_protocol_engine, + failedCommandId=None, ) assert result.content.data == command_once_added @@ -132,6 +134,33 @@ def _stub_queued_command_state(*_a: object, **_k: object) -> pe_commands.Command decoy.verify(await mock_protocol_engine.wait_for_command("command-id"), times=0) +async def test_create_command_with_failed_command_raises( + decoy: Decoy, + mock_protocol_engine: ProtocolEngine, +) -> None: + """It should return 400 bad request.""" + command_create = pe_commands.HomeCreate(params=pe_commands.HomeParams()) + + decoy.when( + mock_protocol_engine.add_command( + pe_commands.HomeCreate( + params=pe_commands.HomeParams(), + intent=pe_commands.CommandIntent.SETUP, + ), + failed_command_id="123", + ) + ).then_raise(pe_errors.CommandNotAllowedError()) + + with pytest.raises(ApiError): + await create_run_command( + RequestModelWithCommandCreate(data=command_create), + waitUntilComplete=False, + timeout=42, + protocol_engine=mock_protocol_engine, + failedCommandId="123", + ) + + async def test_create_run_command_blocking_completion( decoy: Decoy, mock_protocol_engine: ProtocolEngine, @@ -171,7 +200,7 @@ def _stub_completed_command_state(*_a: object, **_k: object) -> None: mock_protocol_engine.state_view.commands.get("command-id") ).then_return(command_once_completed) - decoy.when(mock_protocol_engine.add_command(command_request)).then_do( + decoy.when(mock_protocol_engine.add_command(command_request, None)).then_do( _stub_queued_command_state ) @@ -184,6 +213,7 @@ def _stub_completed_command_state(*_a: object, **_k: object) -> None: waitUntilComplete=True, timeout=999, protocol_engine=mock_protocol_engine, + failedCommandId=None, ) assert result.content.data == command_once_completed @@ -200,7 +230,7 @@ async def test_add_conflicting_setup_command( intent=pe_commands.CommandIntent.SETUP, ) - decoy.when(mock_protocol_engine.add_command(command_request)).then_raise( + decoy.when(mock_protocol_engine.add_command(command_request, None)).then_raise( pe_errors.SetupCommandNotAllowedError("oh no") ) @@ -209,6 +239,7 @@ async def test_add_conflicting_setup_command( request_body=RequestModelWithCommandCreate(data=command_request), waitUntilComplete=False, protocol_engine=mock_protocol_engine, + failedCommandId=None, ) assert exc_info.value.status_code == 409 @@ -228,7 +259,7 @@ async def test_add_command_to_stopped_engine( intent=pe_commands.CommandIntent.SETUP, ) - decoy.when(mock_protocol_engine.add_command(command_request)).then_raise( + decoy.when(mock_protocol_engine.add_command(command_request, None)).then_raise( pe_errors.RunStoppedError("oh no") ) @@ -237,6 +268,7 @@ async def test_add_command_to_stopped_engine( request_body=RequestModelWithCommandCreate(data=command_request), waitUntilComplete=False, protocol_engine=mock_protocol_engine, + failedCommandId=None, ) assert exc_info.value.status_code == 409 diff --git a/robot-server/tests/runs/test_engine_store.py b/robot-server/tests/runs/test_engine_store.py index 7a1f79b903a..330e974be9c 100644 --- a/robot-server/tests/runs/test_engine_store.py +++ b/robot-server/tests/runs/test_engine_store.py @@ -1,12 +1,12 @@ """Tests for the EngineStore interface.""" from datetime import datetime -from pathlib import Path import pytest from decoy import Decoy, matchers from opentrons_shared_data import get_shared_data_root from opentrons_shared_data.robot.dev_types import RobotType +from opentrons.protocol_engine.errors.exceptions import EStopActivatedError from opentrons.types import DeckSlotName from opentrons.hardware_control import HardwareControlAPI, API from opentrons.hardware_control.types import EstopStateNotification, EstopState @@ -23,7 +23,7 @@ EngineStore, EngineConflictError, NoRunnerEnginePairError, - get_estop_listener, + handle_estop_event, ) @@ -33,7 +33,7 @@ def mock_notify_publishers() -> None: @pytest.fixture -def subject(decoy: Decoy, hardware_api: HardwareControlAPI) -> EngineStore: +async def subject(decoy: Decoy, hardware_api: HardwareControlAPI) -> EngineStore: """Get a EngineStore test subject.""" return EngineStore( hardware_api=hardware_api, @@ -45,7 +45,7 @@ def subject(decoy: Decoy, hardware_api: HardwareControlAPI) -> EngineStore: @pytest.fixture -async def json_protocol_source(tmp_path: Path) -> ProtocolSource: +async def json_protocol_source() -> ProtocolSource: """Get a protocol source fixture.""" simple_protocol = ( get_shared_data_root() / "protocol" / "fixtures" / "6" / "simpleV6.json" @@ -70,7 +70,6 @@ async def test_create_engine(subject: EngineStore) -> None: async def test_create_engine_with_protocol( - decoy: Decoy, subject: EngineStore, json_protocol_source: ProtocolSource, ) -> None: @@ -311,22 +310,30 @@ async def test_estop_callback( """The callback should stop an active engine.""" engine_store = decoy.mock(cls=EngineStore) - subject = get_estop_listener(engine_store=engine_store) - - decoy.when(engine_store.current_run_id).then_return(None, "fake_run_id") - disengage_event = EstopStateNotification( old_state=EstopState.PHYSICALLY_ENGAGED, new_state=EstopState.LOGICALLY_ENGAGED ) - - subject(disengage_event) - engage_event = EstopStateNotification( old_state=EstopState.LOGICALLY_ENGAGED, new_state=EstopState.PHYSICALLY_ENGAGED ) - subject(engage_event) - - subject(engage_event) + decoy.when(engine_store.current_run_id).then_return(None) + await handle_estop_event(engine_store, disengage_event) + decoy.verify( + engine_store.engine.estop(), + ignore_extra_args=True, + times=0, + ) + decoy.verify( + await engine_store.engine.finish(), + ignore_extra_args=True, + times=0, + ) - decoy.verify(engine_store.engine.estop(maintenance_run=False), times=1) + decoy.when(engine_store.current_run_id).then_return("fake-run-id") + await handle_estop_event(engine_store, engage_event) + decoy.verify( + engine_store.engine.estop(), + await engine_store.engine.finish(error=matchers.IsA(EStopActivatedError)), + times=1, + ) diff --git a/robot-server/tests/runs/test_run_controller.py b/robot-server/tests/runs/test_run_controller.py index 5bf5778c486..71fc92f8466 100644 --- a/robot-server/tests/runs/test_run_controller.py +++ b/robot-server/tests/runs/test_run_controller.py @@ -11,8 +11,10 @@ commands as pe_commands, errors as pe_errors, ) +from opentrons.protocol_engine.types import RunTimeParameter, BooleanParameter from opentrons.protocol_runner import RunResult, JsonRunner, PythonAndLegacyRunner +from robot_server.service.notifications import RunsPublisher from robot_server.service.task_runner import TaskRunner from robot_server.runs.action_models import RunAction, RunActionType from robot_server.runs.engine_store import EngineStore @@ -40,6 +42,12 @@ def mock_task_runner(decoy: Decoy) -> TaskRunner: return decoy.mock(cls=TaskRunner) +@pytest.fixture() +def mock_runs_publisher(decoy: Decoy) -> RunsPublisher: + """Get a mock RunsPublisher.""" + return decoy.mock(cls=RunsPublisher) + + @pytest.fixture def run_id() -> str: """A run identifier value.""" @@ -60,6 +68,19 @@ def engine_state_summary() -> StateSummary: ) +@pytest.fixture() +def run_time_parameters() -> List[RunTimeParameter]: + """Get a RunTimeParameter list.""" + return [ + BooleanParameter( + displayName="Display Name", + variableName="variable_name", + value=False, + default=True, + ) + ] + + @pytest.fixture def protocol_commands() -> List[pe_commands.Command]: """Get a StateSummary value object.""" @@ -76,6 +97,7 @@ def subject( mock_engine_store: EngineStore, mock_run_store: RunStore, mock_task_runner: TaskRunner, + mock_runs_publisher: RunsPublisher, ) -> RunController: """Get a RunController test subject.""" return RunController( @@ -83,6 +105,7 @@ def subject( engine_store=mock_engine_store, run_store=mock_run_store, task_runner=mock_task_runner, + runs_publisher=mock_runs_publisher, ) @@ -121,7 +144,9 @@ async def test_create_play_action_to_start( mock_engine_store: EngineStore, mock_run_store: RunStore, mock_task_runner: TaskRunner, + mock_runs_publisher: RunsPublisher, engine_state_summary: StateSummary, + run_time_parameters: List[RunTimeParameter], protocol_commands: List[pe_commands.Command], run_id: str, subject: RunController, @@ -153,7 +178,7 @@ async def test_create_play_action_to_start( RunResult( commands=protocol_commands, state_summary=engine_state_summary, - parameters=[], + parameters=run_time_parameters, ) ) @@ -164,7 +189,9 @@ async def test_create_play_action_to_start( run_id=run_id, summary=engine_state_summary, commands=protocol_commands, + run_time_parameters=run_time_parameters, ), + await mock_runs_publisher.publish_pre_serialized_commands_notification(run_id), times=1, ) diff --git a/robot-server/tests/runs/test_run_data_manager.py b/robot-server/tests/runs/test_run_data_manager.py index ba4ceec8799..12ced28fdb0 100644 --- a/robot-server/tests/runs/test_run_data_manager.py +++ b/robot-server/tests/runs/test_run_data_manager.py @@ -1,5 +1,5 @@ """Tests for RunDataManager.""" -from typing import Optional +from typing import Optional, List import pytest from datetime import datetime @@ -23,7 +23,11 @@ from robot_server.protocols.protocol_store import ProtocolResource from robot_server.runs.engine_store import EngineStore, EngineConflictError -from robot_server.runs.run_data_manager import RunDataManager, RunNotCurrentError +from robot_server.runs.run_data_manager import ( + RunDataManager, + RunNotCurrentError, + PreSerializedCommandsNotAvailableError, +) from robot_server.runs.run_models import Run, BadRun, RunNotFoundError, RunDataError from robot_server.runs.run_store import ( RunStore, @@ -85,6 +89,19 @@ def engine_state_summary() -> StateSummary: ) +@pytest.fixture() +def run_time_parameters() -> List[pe_types.RunTimeParameter]: + """Get a RunTimeParameter list.""" + return [ + pe_types.BooleanParameter( + displayName="Display Name", + variableName="variable_name", + value=False, + default=True, + ) + ] + + @pytest.fixture def run_resource() -> RunResource: """Get a StateSummary value object.""" @@ -299,6 +316,7 @@ async def test_get_current_run( mock_run_store: RunStore, subject: RunDataManager, engine_state_summary: StateSummary, + run_time_parameters: List[pe_types.RunTimeParameter], run_resource: RunResource, ) -> None: """It should get the current run from the engine.""" @@ -309,6 +327,9 @@ async def test_get_current_run( decoy.when(mock_engine_store.engine.state_view.get_summary()).then_return( engine_state_summary ) + decoy.when(mock_engine_store.runner.run_time_parameters).then_return( + run_time_parameters + ) result = subject.get(run_id=run_id) @@ -325,6 +346,7 @@ async def test_get_current_run( pipettes=engine_state_summary.pipettes, modules=engine_state_summary.modules, liquids=engine_state_summary.liquids, + runTimeParameters=run_time_parameters, ) assert subject.current_run_id == run_id @@ -335,6 +357,7 @@ async def test_get_historical_run( mock_run_store: RunStore, subject: RunDataManager, engine_state_summary: StateSummary, + run_time_parameters: List[pe_types.RunTimeParameter], run_resource: RunResource, ) -> None: """It should get a historical run from the store.""" @@ -344,6 +367,9 @@ async def test_get_historical_run( decoy.when(mock_run_store.get_state_summary(run_id=run_id)).then_return( engine_state_summary ) + decoy.when(mock_run_store.get_run_time_parameters(run_id=run_id)).then_return( + run_time_parameters + ) decoy.when(mock_engine_store.current_run_id).then_return("some other id") result = subject.get(run_id=run_id) @@ -361,6 +387,7 @@ async def test_get_historical_run( pipettes=engine_state_summary.pipettes, modules=engine_state_summary.modules, liquids=engine_state_summary.liquids, + runTimeParameters=run_time_parameters, ) @@ -370,6 +397,7 @@ async def test_get_historical_run_no_data( mock_run_store: RunStore, subject: RunDataManager, run_resource: RunResource, + run_time_parameters: List[pe_types.RunTimeParameter], ) -> None: """It should get a historical run from the store.""" run_id = "hello world" @@ -380,6 +408,9 @@ async def test_get_historical_run_no_data( decoy.when(mock_run_store.get_state_summary(run_id=run_id)).then_return( BadStateSummary(dataError=state_exc) ) + decoy.when(mock_run_store.get_run_time_parameters(run_id=run_id)).then_return( + run_time_parameters + ) decoy.when(mock_engine_store.current_run_id).then_return("some other id") result = subject.get(run_id=run_id) @@ -398,6 +429,7 @@ async def test_get_historical_run_no_data( pipettes=[], modules=[], liquids=[], + runTimeParameters=run_time_parameters, ) @@ -417,6 +449,14 @@ async def test_get_all_runs( modules=[LoadedModule.construct(id="current-module-id")], # type: ignore[call-arg] liquids=[Liquid(id="some-liquid-id", displayName="liquid", description="desc")], ) + current_run_time_parameters: List[pe_types.RunTimeParameter] = [ + pe_types.BooleanParameter( + displayName="Current Bool", + variableName="current bool", + value=False, + default=True, + ) + ] historical_run_data = StateSummary( status=EngineStatus.STOPPED, @@ -427,6 +467,14 @@ async def test_get_all_runs( modules=[LoadedModule.construct(id="old-module-id")], # type: ignore[call-arg] liquids=[], ) + historical_run_time_parameters: List[pe_types.RunTimeParameter] = [ + pe_types.BooleanParameter( + displayName="Old Bool", + variableName="Old bool", + value=True, + default=False, + ) + ] current_run_resource = RunResource( ok=True, @@ -448,9 +496,15 @@ async def test_get_all_runs( decoy.when(mock_engine_store.engine.state_view.get_summary()).then_return( current_run_data ) + decoy.when(mock_engine_store.runner.run_time_parameters).then_return( + current_run_time_parameters + ) decoy.when(mock_run_store.get_state_summary("historical-run")).then_return( historical_run_data ) + decoy.when(mock_run_store.get_run_time_parameters("historical-run")).then_return( + historical_run_time_parameters + ) decoy.when(mock_run_store.get_all(length=20)).then_return( [historical_run_resource, current_run_resource] ) @@ -471,6 +525,7 @@ async def test_get_all_runs( pipettes=historical_run_data.pipettes, modules=historical_run_data.modules, liquids=historical_run_data.liquids, + runTimeParameters=historical_run_time_parameters, ), Run( current=True, @@ -485,6 +540,7 @@ async def test_get_all_runs( pipettes=current_run_data.pipettes, modules=current_run_data.modules, liquids=current_run_data.liquids, + runTimeParameters=current_run_time_parameters, ), ] @@ -526,10 +582,12 @@ async def test_delete_historical_run( async def test_update_current( decoy: Decoy, engine_state_summary: StateSummary, + run_time_parameters: List[pe_types.RunTimeParameter], run_resource: RunResource, run_command: commands.Command, mock_engine_store: EngineStore, mock_run_store: RunStore, + mock_runs_publisher: RunsPublisher, subject: RunDataManager, ) -> None: """It should persist the current run and clear the engine on current=false.""" @@ -537,7 +595,9 @@ async def test_update_current( decoy.when(mock_engine_store.current_run_id).then_return(run_id) decoy.when(await mock_engine_store.clear()).then_return( RunResult( - commands=[run_command], state_summary=engine_state_summary, parameters=[] + commands=[run_command], + state_summary=engine_state_summary, + parameters=run_time_parameters, ) ) @@ -546,11 +606,16 @@ async def test_update_current( run_id=run_id, summary=engine_state_summary, commands=[run_command], + run_time_parameters=run_time_parameters, ) ).then_return(run_resource) result = await subject.update(run_id=run_id, current=False) + decoy.verify( + await mock_runs_publisher.publish_pre_serialized_commands_notification(run_id), + times=1, + ) assert result == Run( current=False, id=run_resource.run_id, @@ -564,6 +629,7 @@ async def test_update_current( pipettes=engine_state_summary.pipettes, modules=engine_state_summary.modules, liquids=engine_state_summary.liquids, + runTimeParameters=run_time_parameters, ) @@ -571,10 +637,12 @@ async def test_update_current( async def test_update_current_noop( decoy: Decoy, engine_state_summary: StateSummary, + run_time_parameters: List[pe_types.RunTimeParameter], run_resource: RunResource, run_command: commands.Command, mock_engine_store: EngineStore, mock_run_store: RunStore, + mock_runs_publisher: RunsPublisher, subject: RunDataManager, current: Optional[bool], ) -> None: @@ -584,6 +652,9 @@ async def test_update_current_noop( decoy.when(mock_engine_store.engine.state_view.get_summary()).then_return( engine_state_summary ) + decoy.when(mock_engine_store.runner.run_time_parameters).then_return( + run_time_parameters + ) decoy.when(mock_run_store.get(run_id=run_id)).then_return(run_resource) result = await subject.update(run_id=run_id, current=current) @@ -594,7 +665,9 @@ async def test_update_current_noop( run_id=run_id, summary=matchers.Anything(), commands=matchers.Anything(), + run_time_parameters=matchers.Anything(), ), + await mock_runs_publisher.publish_pre_serialized_commands_notification(run_id), times=0, ) @@ -611,6 +684,7 @@ async def test_update_current_noop( pipettes=engine_state_summary.pipettes, modules=engine_state_summary.modules, liquids=engine_state_summary.liquids, + runTimeParameters=run_time_parameters, ) @@ -634,6 +708,7 @@ async def test_update_current_not_allowed( async def test_create_archives_existing( decoy: Decoy, engine_state_summary: StateSummary, + run_time_parameters: List[pe_types.RunTimeParameter], run_resource: RunResource, run_command: commands.Command, mock_engine_store: EngineStore, @@ -647,7 +722,9 @@ async def test_create_archives_existing( decoy.when(mock_engine_store.current_run_id).then_return(run_id_old) decoy.when(await mock_engine_store.clear()).then_return( RunResult( - commands=[run_command], state_summary=engine_state_summary, parameters=[] + commands=[run_command], + state_summary=engine_state_summary, + parameters=run_time_parameters, ) ) @@ -685,6 +762,7 @@ async def test_create_archives_existing( run_id=run_id_old, summary=engine_state_summary, commands=[run_command], + run_time_parameters=run_time_parameters, ) ) @@ -865,6 +943,38 @@ def test_get_command_from_db_command_not_found( subject.get_command("run-id", "command-id") +def test_get_all_commands_as_preserialized_list( + decoy: Decoy, + subject: RunDataManager, + mock_run_store: RunStore, + mock_engine_store: EngineStore, +) -> None: + """It should return the pre-serialized commands list.""" + decoy.when(mock_engine_store.current_run_id).then_return(None) + decoy.when( + mock_run_store.get_all_commands_as_preserialized_list("run-id") + ).then_return(['{"id": command-1}', '{"id": command-2}']) + assert subject.get_all_commands_as_preserialized_list("run-id") == [ + '{"id": command-1}', + '{"id": command-2}', + ] + + +def test_get_all_commands_as_preserialized_list_errors_for_active_runs( + decoy: Decoy, + subject: RunDataManager, + mock_run_store: RunStore, + mock_engine_store: EngineStore, +) -> None: + """It should raise an error when fetching pre-serialized commands list while run is active.""" + decoy.when(mock_engine_store.current_run_id).then_return("current-run-id") + decoy.when( + mock_engine_store.engine.state_view.commands.get_is_terminal() + ).then_return(False) + with pytest.raises(PreSerializedCommandsNotAvailableError): + subject.get_all_commands_as_preserialized_list("current-run-id") + + async def test_get_current_run_labware_definition( decoy: Decoy, mock_engine_store: EngineStore, diff --git a/robot-server/tests/runs/test_run_store.py b/robot-server/tests/runs/test_run_store.py index 31cabbe56bd..ee7697107f6 100644 --- a/robot-server/tests/runs/test_run_store.py +++ b/robot-server/tests/runs/test_run_store.py @@ -120,6 +120,41 @@ def state_summary() -> StateSummary: ) +@pytest.fixture() +def run_time_parameters() -> List[pe_types.RunTimeParameter]: + """Get a RunTimeParameter list.""" + return [ + pe_types.BooleanParameter( + displayName="Display Name 1", + variableName="variable_name_1", + value=False, + default=True, + ), + pe_types.NumberParameter( + displayName="Display Name 2", + variableName="variable_name_2", + type="int", + min=123.0, + max=456.0, + value=333.0, + default=222.0, + ), + pe_types.EnumParameter( + displayName="Display Name 3", + variableName="variable_name_3", + type="str", + choices=[ + pe_types.EnumChoice( + displayName="Choice Name", + value="cool choice", + ) + ], + default="cooler choice", + value="coolest choice", + ), + ] + + @pytest.fixture def invalid_state_summary() -> StateSummary: """Should fail pydantic validation.""" @@ -164,6 +199,7 @@ def test_update_run_state( subject: RunStore, state_summary: StateSummary, protocol_commands: List[pe_commands.Command], + run_time_parameters: List[pe_types.RunTimeParameter], mock_runs_publisher: mock.Mock, ) -> None: """It should be able to update a run state to the store.""" @@ -184,8 +220,10 @@ def test_update_run_state( run_id="run-id", summary=state_summary, commands=protocol_commands, + run_time_parameters=run_time_parameters, ) run_summary_result = subject.get_state_summary(run_id="run-id") + parameters_result = subject.get_run_time_parameters(run_id="run-id") commands_result = subject.get_commands_slice( run_id="run-id", length=len(protocol_commands), @@ -200,6 +238,7 @@ def test_update_run_state( actions=[action], ) assert run_summary_result == state_summary + assert parameters_result == run_time_parameters assert commands_result.commands == protocol_commands mock_runs_publisher.publish_runs_advise_refetch.assert_called_once_with( run_id="run-id" @@ -217,6 +256,7 @@ def test_update_state_run_not_found( run_id="run-not-found", summary=state_summary, commands=protocol_commands, + run_time_parameters=[], ) @@ -436,7 +476,9 @@ def test_get_state_summary( protocol_id=None, created_at=datetime(year=2021, month=1, day=1, tzinfo=timezone.utc), ) - subject.update_run_state(run_id="run-id", summary=state_summary, commands=[]) + subject.update_run_state( + run_id="run-id", summary=state_summary, commands=[], run_time_parameters=[] + ) result = subject.get_state_summary(run_id="run-id") assert result == state_summary mock_runs_publisher.publish_runs_advise_refetch.assert_called_once_with( @@ -454,7 +496,10 @@ def test_get_state_summary_failure( created_at=datetime(year=2021, month=1, day=1, tzinfo=timezone.utc), ) subject.update_run_state( - run_id="run-id", summary=invalid_state_summary, commands=[] + run_id="run-id", + summary=invalid_state_summary, + commands=[], + run_time_parameters=[], ) result = subject.get_state_summary(run_id="run-id") assert isinstance(result, BadStateSummary) @@ -473,6 +518,62 @@ def test_get_state_summary_none(subject: RunStore) -> None: assert result.dataError.code == ErrorCodes.INVALID_STORED_DATA +def test_get_run_time_parameters( + subject: RunStore, + state_summary: StateSummary, + run_time_parameters: List[pe_types.RunTimeParameter], +) -> None: + """It should be able to get store run time parameters.""" + subject.insert( + run_id="run-id", + protocol_id=None, + created_at=datetime(year=2021, month=1, day=1, tzinfo=timezone.utc), + ) + subject.update_run_state( + run_id="run-id", + summary=state_summary, + commands=[], + run_time_parameters=run_time_parameters, + ) + result = subject.get_run_time_parameters(run_id="run-id") + assert result == run_time_parameters + + +def test_get_run_time_parameters_invalid( + subject: RunStore, + state_summary: StateSummary, +) -> None: + """It should return an empty list if there invalid parameters.""" + bad_parameters = [pe_types.BooleanParameter.construct(foo="bar")] # type: ignore[call-arg] + subject.insert( + run_id="run-id", + protocol_id=None, + created_at=datetime(year=2021, month=1, day=1, tzinfo=timezone.utc), + ) + subject.update_run_state( + run_id="run-id", + summary=state_summary, + commands=[], + run_time_parameters=bad_parameters, # type: ignore[arg-type] + ) + result = subject.get_run_time_parameters(run_id="run-id") + assert result == [] + + +def test_get_run_time_parameters_none( + subject: RunStore, + state_summary: StateSummary, +) -> None: + """It should return an empty list if there are no run time parameters associated.""" + subject.insert( + run_id="run-id", + protocol_id=None, + created_at=datetime(year=2021, month=1, day=1, tzinfo=timezone.utc), + ) + result = subject.get_run_time_parameters(run_id="run-id") + assert result == [] + + def test_has_run_id(subject: RunStore) -> None: """It should tell us if a given ID is in the store.""" subject.insert( @@ -503,6 +604,7 @@ def test_get_command( run_id="run-id", summary=state_summary, commands=protocol_commands, + run_time_parameters=[], ) result = subject.get_command(run_id="run-id", command_id="pause-2") @@ -532,6 +634,7 @@ def test_get_command_raise_exception( run_id="run-id", summary=state_summary, commands=protocol_commands, + run_time_parameters=[], ) with pytest.raises(expected_exception): subject.get_command(run_id=input_run_id, command_id=input_command_id) @@ -552,6 +655,7 @@ def test_get_command_slice( run_id="run-id", summary=state_summary, commands=protocol_commands, + run_time_parameters=[], ) result = subject.get_commands_slice( run_id="run-id", cursor=0, length=len(protocol_commands) @@ -598,6 +702,7 @@ def test_get_commands_slice_clamping( run_id="run-id", summary=state_summary, commands=protocol_commands, + run_time_parameters=[], ) result = subject.get_commands_slice( run_id="run-id", cursor=input_cursor, length=input_length @@ -629,3 +734,31 @@ def test_get_commands_slice_run_not_found(subject: RunStore) -> None: ) with pytest.raises(RunNotFoundError): subject.get_commands_slice(run_id="not-run-id", cursor=1, length=3) + + +def test_get_all_commands_as_preserialized_list( + subject: RunStore, + protocol_commands: List[pe_commands.Command], + state_summary: StateSummary, +) -> None: + """It should get all commands stored in DB as a pre-serialized list.""" + subject.insert( + run_id="run-id", + protocol_id=None, + created_at=datetime(year=2021, month=1, day=1, tzinfo=timezone.utc), + ) + subject.update_run_state( + run_id="run-id", + summary=state_summary, + commands=protocol_commands, + run_time_parameters=[], + ) + result = subject.get_all_commands_as_preserialized_list(run_id="run-id") + assert result == [ + '{"id": "pause-1", "createdAt": "2021-01-01T00:00:00", "commandType": "waitForResume",' + ' "key": "command-key", "status": "succeeded", "params": {"message": "hello world"}, "result": {}}', + '{"id": "pause-2", "createdAt": "2022-02-02T00:00:00", "commandType": "waitForResume",' + ' "key": "command-key", "status": "succeeded", "params": {"message": "hey world"}, "result": {}}', + '{"id": "pause-3", "createdAt": "2023-03-03T00:00:00", "commandType": "waitForResume",' + ' "key": "command-key", "status": "succeeded", "params": {"message": "sup world"}, "result": {}}', + ] diff --git a/robot-server/tests/service/notifications/publishers/test_deck_configuration_publisher.py b/robot-server/tests/service/notifications/publishers/test_deck_configuration_publisher.py new file mode 100644 index 00000000000..3f2b8481967 --- /dev/null +++ b/robot-server/tests/service/notifications/publishers/test_deck_configuration_publisher.py @@ -0,0 +1,31 @@ +"""Tests for the deck configuration publisher.""" +import pytest +from unittest.mock import AsyncMock + +from robot_server.service.notifications import DeckConfigurationPublisher, Topics + + +@pytest.fixture +def notification_client() -> AsyncMock: + """Mocked notification client.""" + return AsyncMock() + + +@pytest.fixture +def deck_configuration_publisher( + notification_client: AsyncMock, +) -> DeckConfigurationPublisher: + """Instantiate DeckConfigurationPublisher.""" + return DeckConfigurationPublisher(notification_client) + + +@pytest.mark.asyncio +async def test_publish_current_maintenance_run( + notification_client: AsyncMock, + deck_configuration_publisher: DeckConfigurationPublisher, +) -> None: + """It should publish a notify flag for deck configuration updates.""" + await deck_configuration_publisher.publish_deck_configuration() + notification_client.publish_advise_refetch_async.assert_awaited_once_with( + topic=Topics.DECK_CONFIGURATION + ) diff --git a/robot-server/tests/service/notifications/publishers/test_runs_publisher.py b/robot-server/tests/service/notifications/publishers/test_runs_publisher.py index 29797dbf83a..f8fdaf0cf9f 100644 --- a/robot-server/tests/service/notifications/publishers/test_runs_publisher.py +++ b/robot-server/tests/service/notifications/publishers/test_runs_publisher.py @@ -4,7 +4,7 @@ from unittest.mock import MagicMock, AsyncMock from robot_server.service.notifications import RunsPublisher, Topics -from opentrons.protocol_engine import CurrentCommand, EngineStatus +from opentrons.protocol_engine import CurrentCommand, EngineStatus, StateSummary def mock_curent_command(command_id: str) -> CurrentCommand: @@ -17,6 +17,19 @@ def mock_curent_command(command_id: str) -> CurrentCommand: ) +def mock_state_summary(run_id: str) -> StateSummary: + return StateSummary.construct( + status=EngineStatus.FAILED, + errors=[], + labware=[], + pipettes=[], + modules=[], + labwareOffsets=[], + startedAt=None, + completedAt=datetime(year=2021, month=1, day=1), + ) + + @pytest.fixture def notification_client() -> AsyncMock: """Mocked notification client.""" @@ -71,7 +84,7 @@ async def test_clean_up_current_run( """It should publish to appropriate topics at the end of a run.""" await runs_publisher.initialize("1234", AsyncMock(), AsyncMock()) - await runs_publisher.clean_up_current_run() + await runs_publisher.clean_up_run(run_id="1234") notification_client.publish_advise_refetch_async.assert_any_await(topic=Topics.RUNS) notification_client.publish_advise_refetch_async.assert_any_await( @@ -80,6 +93,12 @@ async def test_clean_up_current_run( notification_client.publish_advise_unsubscribe_async.assert_any_await( topic=f"{Topics.RUNS}/1234" ) + notification_client.publish_advise_unsubscribe_async.assert_any_await( + topic=Topics.RUNS_CURRENT_COMMAND + ) + notification_client.publish_advise_unsubscribe_async.assert_any_await( + topic=f"{Topics.RUNS_PRE_SERIALIZED_COMMANDS}/1234" + ) @pytest.mark.asyncio @@ -143,3 +162,24 @@ async def test_handle_engine_status_change( notification_client.publish_advise_refetch_async.assert_any_await( topic=f"{Topics.RUNS}/1234" ) + + +async def test_publish_pre_serialized_commannds_notif( + runs_publisher: RunsPublisher, notification_client: AsyncMock +) -> None: + """It should send out a notification for pre serialized commands.""" + await runs_publisher.initialize( + "1234", lambda _: mock_curent_command("command1"), AsyncMock() + ) + + assert runs_publisher._run_hooks + assert runs_publisher._engine_state_slice + assert notification_client.publish_advise_refetch_async.call_count == 2 + + await runs_publisher.publish_pre_serialized_commands_notification(run_id="1234") + + assert notification_client.publish_advise_refetch_async.call_count == 3 + + notification_client.publish_advise_refetch_async.assert_any_await( + topic=f"{Topics.RUNS_PRE_SERIALIZED_COMMANDS}/1234" + ) diff --git a/robot-server/tests/service/notifications/test_publisher_notifier.py b/robot-server/tests/service/notifications/test_publisher_notifier.py index 125cfdd1806..02ee12f3ee6 100644 --- a/robot-server/tests/service/notifications/test_publisher_notifier.py +++ b/robot-server/tests/service/notifications/test_publisher_notifier.py @@ -1,15 +1,16 @@ import asyncio from unittest.mock import Mock, MagicMock +from opentrons.util.change_notifier import ChangeNotifier + from robot_server.service.notifications import ( PublisherNotifier, - ChangeNotifier, ) async def test_initialize() -> None: """It should create a new task.""" - publisher_notifier = PublisherNotifier() + publisher_notifier = PublisherNotifier(ChangeNotifier()) await publisher_notifier._initialize() @@ -28,7 +29,7 @@ def test_notify_publishers() -> None: def test_register_publish_callbacks() -> None: """It should extend the list of callbacks within a given list of callbacks.""" - publisher_notifier = PublisherNotifier() + publisher_notifier = PublisherNotifier(ChangeNotifier()) callback1 = Mock() callback2 = Mock() diff --git a/scripts/deploy/create-release.js b/scripts/deploy/create-release.js index eb4db62bd2a..3b804506a2e 100644 --- a/scripts/deploy/create-release.js +++ b/scripts/deploy/create-release.js @@ -22,12 +22,6 @@ const parseArgs = require('./lib/parseArgs') const conventionalChangelog = require('conventional-changelog') const semver = require('semver') const { Octokit } = require('@octokit/rest') -const { - detailsFromTag, - tagFromDetails, - prefixForProject, - monorepoGit, -} = require('../git-version') const USAGE = '\nUsage:\n node ./scripts/deploy/create-release [--deploy] [--allow-old]' @@ -81,9 +75,35 @@ function versionPrevious(currentVersion, previousVersions) { return releasesOfGEQKind.length === 0 ? null : releasesOfGEQKind[0] } +async function gitVersion() { + let imported + if (imported === undefined) { + imported = await import('../git-version.mjs') + } + return imported +} + +async function monorepoGit() { + return await (await gitVersion()).monorepoGit() +} + +async function detailsFromTag(tag) { + return await (await gitVersion()).detailsFromTag(tag) +} + +async function tagFromDetails(project, version) { + return (await gitVersion()).tagFromDetails(project, version) +} + +async function prefixForProject(project) { + return (await gitVersion()).prefixForProject(project) +} + async function versionDetailsFromGit(tag, allowOld) { if (!allowOld) { - const last100 = await monorepoGit().log({ from: 'HEAD~100', to: 'HEAD' }) + const git = await monorepoGit() + const last100 = await git.log({ from: 'HEAD~100', to: 'HEAD' }) + if (!last100.all.some(commit => commit.refs.includes('tag: ' + tag))) { throw new Error( `Cannot find tag ${tag} in last 100 commits. You must run this script from a ref with ` + @@ -94,9 +114,8 @@ async function versionDetailsFromGit(tag, allowOld) { } const [project, currentVersion] = detailsFromTag(tag) - - const allTags = (await monorepoGit().tags([prefixForProject(project) + '*'])) - .all + const prefix = await prefixForProject(project) + const allTags = (await monorepoGit().tags([prefix + '*'])).all if (!allTags.includes(tag)) { throw new Error( `Tag ${tag} does not exist - create it before running this script` @@ -123,14 +142,15 @@ async function buildChangelog(project, currentVersion, previousVersion) { `## ${currentVersion}` + `\nFirst release for ${titleForProject(project)}` ) } - const previousTag = tagFromDetails(project, previousVersion) - + const previousTag = await tagFromDetails(project, previousVersion) + const currentTag = await tagFromDetails(project, currentVersion) + const prefix = await prefixForProject(Project) const changelogStream = conventionalChangelog( - { preset: 'angular', tagPrefix: prefixForProject(project) }, + { preset: 'angular', tagPrefix: prefix }, { version: currentVersion, - currentTag: tagFromDetails(project, currentVersion), - previousTag: previousTag, + currentTag, + previousTag, host: 'https://github.com', owner: REPO_DETAILS.owner, repository: REPO_DETAILS.repo, @@ -203,6 +223,7 @@ async function main() { currentVersion, previousVersion, ] = await versionDetailsFromGit(tag, allowOld) + const prefix = await prefixForProject(project) const changelog = await buildChangelog( project, currentVersion, @@ -211,8 +232,8 @@ async function main() { const truncatedChangelog = truncateAndAnnotate( changelog, 10000, - prefixForProject(project) + previousVersion, - prefixForProject(project) + currentVersion + prefix + previousVersion, + prefix + currentVersion ) return await createRelease( token, diff --git a/scripts/git-version.js b/scripts/git-version.mjs similarity index 79% rename from scripts/git-version.js rename to scripts/git-version.mjs index a2dab912f23..7b4d364d0da 100644 --- a/scripts/git-version.js +++ b/scripts/git-version.mjs @@ -15,23 +15,24 @@ // What that all boils down to is that we need, and this module provides, an interface to get the version of a // given project that currently exists in the monorepo. -const git = require('simple-git') -const { dirname } = require('path') -const REPO_BASE = dirname(__dirname) +import git from 'simple-git' +import { dirname } from 'path' +import { fileURLToPath } from 'url' +const REPO_BASE = dirname(dirname(fileURLToPath(import.meta.url))) -function monorepoGit() { +export function monorepoGit() { return git({ baseDir: REPO_BASE }) } -const detailsFromTag = tag => +export const detailsFromTag = tag => tag.includes('@') ? tag.split('@') : ['robot-stack', tag.substring(1)] -function tagFromDetails(project, version) { +export function tagFromDetails(project, version) { const prefix = prefixForProject(project) return `${prefix}${version}` } -function prefixForProject(project) { +export function prefixForProject(project) { if (project === 'robot-stack') { return 'v' } else { @@ -39,7 +40,7 @@ function prefixForProject(project) { } } -async function latestTagForProject(project) { +export async function latestTagForProject(project) { return ( await monorepoGit().raw([ 'describe', @@ -50,7 +51,7 @@ async function latestTagForProject(project) { ).trim() } -async function versionForProject(project) { +export async function versionForProject(project) { return latestTagForProject(project) .then(tag => detailsFromTag(tag)[1]) .catch(error => { @@ -60,12 +61,3 @@ async function versionForProject(project) { return '0.0.0-dev' }) } - -module.exports = { - detailsFromTag, - tagFromDetails, - prefixForProject, - latestTagForProject, - versionForProject, - monorepoGit, -} diff --git a/scripts/update-releases-json.js b/scripts/update-releases-json.js index 3286256c42b..d7aa9b0ca21 100644 --- a/scripts/update-releases-json.js +++ b/scripts/update-releases-json.js @@ -4,8 +4,6 @@ const fs = require('fs/promises') // Updates a releases historical manifest with a release's version. -const versionFinder = require('./git-version') - const parseArgs = require('./deploy/lib/parseArgs') const USAGE = '\nUsage:\n node ./scripts/update-releases-json ' @@ -63,6 +61,7 @@ async function main() { } console.log(`Updating ${releasesPath} with artifacts from ${artifactDirPath}`) const releasesData = await readOrDefaultReleases(releasesPath) + const versionFinder = await import('./git-version.mjs') const version = await versionFinder.versionForProject(project) console.log(`Adding data for ${version}`) releasesData.production[version] = { diff --git a/setup-vitest.ts b/setup-vitest.ts index 07bd135137d..4488cc17bf6 100644 --- a/setup-vitest.ts +++ b/setup-vitest.ts @@ -7,9 +7,22 @@ vi.mock('electron-store') vi.mock('electron-updater') vi.mock('electron') vi.mock('./app/src/redux/shell/remote') +vi.mock('./app/src/resources/useNotifyService', async () => { + const actual = await vi.importActual('./app/src/resources/useNotifyService') + return { + ...actual, + useNotifyService: () => ({ + notifyOnSettled: vi.fn(), + isNotifyEnabled: true, + }), + } +}) process.env.OT_PD_VERSION = 'fake_PD_version' global._PKG_VERSION_ = 'test environment' +global._OPENTRONS_PROJECT_ = 'robotics' +global._PKG_PRODUCT_NAME_ = 'test product' +global._PKG_BUGS_URL_ = 'http://bugs.contoso.com' afterEach(() => { cleanup() diff --git a/shared-data/command/schemas/8.json b/shared-data/command/schemas/8.json index a17be9ee690..5aea97fe94f 100644 --- a/shared-data/command/schemas/8.json +++ b/shared-data/command/schemas/8.json @@ -19,6 +19,7 @@ "home": "#/definitions/HomeCreate", "retractAxis": "#/definitions/RetractAxisCreate", "loadLabware": "#/definitions/LoadLabwareCreate", + "reloadLabware": "#/definitions/ReloadLabwareCreate", "loadLiquid": "#/definitions/LoadLiquidCreate", "loadModule": "#/definitions/LoadModuleCreate", "loadPipette": "#/definitions/LoadPipetteCreate", @@ -112,6 +113,9 @@ { "$ref": "#/definitions/LoadLabwareCreate" }, + { + "$ref": "#/definitions/ReloadLabwareCreate" + }, { "$ref": "#/definitions/LoadLiquidCreate" }, @@ -339,7 +343,7 @@ "CommandIntent": { "title": "CommandIntent", "description": "Run intent for a given command.\n\nProps:\n PROTOCOL: the command is part of the protocol run itself.\n SETUP: the command is part of the setup phase of a run.", - "enum": ["protocol", "setup"], + "enum": ["protocol", "setup", "fixit"], "type": "string" }, "AspirateCreate": { @@ -1407,6 +1411,49 @@ }, "required": ["params"] }, + "ReloadLabwareParams": { + "title": "ReloadLabwareParams", + "description": "Payload required to load a labware into a slot.", + "type": "object", + "properties": { + "labwareId": { + "title": "Labwareid", + "description": "The already-loaded labware instance to update.", + "type": "string" + } + }, + "required": ["labwareId"] + }, + "ReloadLabwareCreate": { + "title": "ReloadLabwareCreate", + "description": "Reload labware command creation request.", + "type": "object", + "properties": { + "commandType": { + "title": "Commandtype", + "default": "reloadLabware", + "enum": ["reloadLabware"], + "type": "string" + }, + "params": { + "$ref": "#/definitions/ReloadLabwareParams" + }, + "intent": { + "description": "The reason the command was added. If not specified or `protocol`, the command will be treated as part of the protocol run itself, and added to the end of the existing command queue.\n\nIf `setup`, the command will be treated as part of run setup. A setup command may only be enqueued if the run has not started.\n\nUse setup commands for activities like pre-run calibration checks and module setup, like pre-heating.", + "allOf": [ + { + "$ref": "#/definitions/CommandIntent" + } + ] + }, + "key": { + "title": "Key", + "description": "A key value, unique in this run, that can be used to track the same logical command across multiple runs of the same protocol. If a value is not provided, one will be generated.", + "type": "string" + } + }, + "required": ["params"] + }, "LoadLiquidParams": { "title": "LoadLiquidParams", "description": "Payload required to load a liquid into a well.", @@ -2582,6 +2629,12 @@ "enum": ["present", "absent", "unknown"], "type": "string" }, + "InstrumentSensorId": { + "title": "InstrumentSensorId", + "description": "Primary and secondary sensor ids.", + "enum": ["primary", "secondary", "both"], + "type": "string" + }, "VerifyTipPresenceParams": { "title": "VerifyTipPresenceParams", "description": "Payload required for a VerifyTipPresence command.", @@ -2599,6 +2652,14 @@ "$ref": "#/definitions/TipPresenceStatus" } ] + }, + "followSingularSensor": { + "description": "The sensor id to follow if the other can be ignored.", + "allOf": [ + { + "$ref": "#/definitions/InstrumentSensorId" + } + ] } }, "required": ["pipetteId", "expectedState"] diff --git a/shared-data/command/types/pipetting.ts b/shared-data/command/types/pipetting.ts index a7364add50b..57a11a0621e 100644 --- a/shared-data/command/types/pipetting.ts +++ b/shared-data/command/types/pipetting.ts @@ -282,6 +282,7 @@ interface WellLocationParam { interface VerifyTipPresenceParams extends PipetteIdentityParams { expectedState?: 'present' | 'absent' + followSingularSensor?: 'primary' | 'secondary' } interface BasicLiquidHandlingResult { diff --git a/shared-data/deck/definitions/5/ot2_short_trash.json b/shared-data/deck/definitions/5/ot2_short_trash.json new file mode 100644 index 00000000000..7d00f8d5773 --- /dev/null +++ b/shared-data/deck/definitions/5/ot2_short_trash.json @@ -0,0 +1,409 @@ +{ + "otId": "ot2_short_trash", + "schemaVersion": 5, + "cornerOffsetFromOrigin": [-115.65, -68.03, 0], + "dimensions": [624.3, 565.2, 0], + "metadata": { + "displayName": "OT-2 Short-Trash Deck", + "tags": ["ot2", "12 slots", "short trash"] + }, + "robot": { + "model": "OT-2 Standard" + }, + "locations": { + "addressableAreas": [ + { + "id": "1", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 1", + "compatibleModuleTypes": [ + "magneticModuleType", + "temperatureModuleType", + "heaterShakerModuleType" + ] + }, + { + "id": "2", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 2", + "compatibleModuleTypes": [ + "magneticModuleType", + "temperatureModuleType", + "heaterShakerModuleType" + ] + }, + { + "id": "3", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 3", + "compatibleModuleTypes": [ + "magneticModuleType", + "temperatureModuleType", + "heaterShakerModuleType" + ] + }, + { + "id": "4", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 4", + "compatibleModuleTypes": [ + "magneticModuleType", + "temperatureModuleType", + "heaterShakerModuleType" + ] + }, + { + "id": "5", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 5", + "compatibleModuleTypes": [ + "magneticModuleType", + "temperatureModuleType", + "heaterShakerModuleType" + ] + }, + { + "id": "6", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 6", + "compatibleModuleTypes": [ + "magneticModuleType", + "temperatureModuleType", + "heaterShakerModuleType" + ] + }, + { + "id": "7", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 7", + "compatibleModuleTypes": [ + "magneticModuleType", + "temperatureModuleType", + "thermocyclerModuleType", + "heaterShakerModuleType" + ] + }, + { + "id": "8", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 8", + "compatibleModuleTypes": [ + "magneticModuleType", + "temperatureModuleType", + "heaterShakerModuleType" + ] + }, + { + "id": "9", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 9", + "compatibleModuleTypes": [ + "magneticModuleType", + "temperatureModuleType", + "heaterShakerModuleType" + ] + }, + { + "id": "10", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 10", + "compatibleModuleTypes": [ + "magneticModuleType", + "temperatureModuleType", + "heaterShakerModuleType" + ] + }, + { + "id": "11", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 11", + "compatibleModuleTypes": [ + "magneticModuleType", + "temperatureModuleType", + "heaterShakerModuleType" + ] + }, + { + "id": "12", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 12", + "compatibleModuleTypes": [] + }, + { + "id": "shortFixedTrash", + "areaType": "fixedTrash", + "offsetFromCutoutFixture": [29.285, -2.835, 0], + "boundingBox": { + "xDimension": 107.11, + "yDimension": 165.67, + "zDimension": 58 + }, + "displayName": "Slot 12/Short Fixed Trash", + "ableToDropTips": true + } + ], + "cutouts": [ + { + "id": "cutout1", + "position": [0.0, 0.0, 0.0], + "displayName": "Cutout 1" + }, + { + "id": "cutout2", + "position": [132.5, 0.0, 0.0], + "displayName": "Cutout 2" + }, + { + "id": "cutout3", + "position": [265.0, 0.0, 0.0], + "displayName": "Cutout 3" + }, + { + "id": "cutout4", + "position": [0.0, 90.5, 0.0], + "displayName": "Cutout 4" + }, + { + "id": "cutout5", + "position": [132.5, 90.5, 0.0], + "displayName": "Cutout 5" + }, + { + "id": "cutout6", + "position": [265.0, 90.5, 0.0], + "displayName": "Cutout 6" + }, + { + "id": "cutout7", + "position": [0.0, 181.0, 0.0], + "displayName": "Cutout 7" + }, + { + "id": "cutout8", + "position": [132.5, 181.0, 0.0], + "displayName": "Cutout 8" + }, + { + "id": "cutout9", + "position": [265.0, 181.0, 0.0], + "displayName": "Cutout 9" + }, + { + "id": "cutout10", + "position": [0.0, 271.5, 0.0], + "displayName": "Slot 10" + }, + { + "id": "cutout11", + "position": [132.5, 271.5, 0.0], + "displayName": "Cutout 11" + }, + { + "id": "cutout12", + "position": [265.0, 271.5, 0.0], + "displayName": "Cutout 12" + } + ], + "calibrationPoints": [ + { + "id": "1BLC", + "position": [12.13, 9.0, 0.0], + "displayName": "Slot 1 Bottom Left Cross" + }, + { + "id": "3BRC", + "position": [380.87, 9.0, 0.0], + "displayName": "Slot 3 Bottom Right Cross" + }, + { + "id": "7TLC", + "position": [12.13, 258.0, 0.0], + "displayName": "Slot 7 Top Left Cross" + }, + { + "id": "9TRC", + "position": [380.87, 258.0, 0.0], + "displayName": "Slot 9 Top Right Cross" + }, + { + "id": "10TLC", + "position": [12.13, 348.5, 0.0], + "displayName": "Slot 10 Top Left Cross" + }, + { + "id": "11TRC", + "position": [248.37, 348.5, 0.0], + "displayName": "Slot 11 Top Right Cross" + }, + { + "id": "1BLD", + "position": [12.13, 6.0, 0.0], + "displayName": "Slot 1 Bottom Left Dot" + }, + { + "id": "3BRD", + "position": [380.87, 6.0, 0.0], + "displayName": "Slot 3 Bottom Right Dot" + }, + { + "id": "7TLD", + "position": [12.13, 261.0, 0.0], + "displayName": "Slot 7 Top Left Dot" + }, + { + "id": "9TRD", + "position": [380.87, 261.0, 0.0], + "displayName": "Slot 9 Top Right Dot" + }, + { + "id": "10TLD", + "position": [12.13, 351.5, 0.0], + "displayName": "Slot 10 Top Left Dot" + }, + { + "id": "11TRD", + "position": [248.37, 351.5, 0.0], + "displayName": "Slot 11 Top Right Dot" + } + ], + "legacyFixtures": [ + { + "id": "fixedTrash", + "slot": "12", + "labware": "opentrons_1_trash_850ml_fixed", + "displayName": "Fixed Trash" + } + ] + }, + "cutoutFixtures": [ + { + "id": "singleStandardSlot", + "expectOpentronsModuleSerialNumber": false, + "mayMountTo": [ + "cutout1", + "cutout2", + "cutout3", + "cutout4", + "cutout5", + "cutout6", + "cutout7", + "cutout8", + "cutout9", + "cutout10", + "cutout11", + "cutout12" + ], + "displayName": "Standard Slot", + "providesAddressableAreas": { + "cutout1": ["1"], + "cutout2": ["2"], + "cutout3": ["3"], + "cutout4": ["4"], + "cutout5": ["5"], + "cutout6": ["6"], + "cutout7": ["7"], + "cutout8": ["8"], + "cutout9": ["9"], + "cutout10": ["10"], + "cutout11": ["11"], + "cutout12": ["12"] + }, + "fixtureGroup": {}, + "height": 0 + }, + { + "id": "fixedTrashSlot", + "expectOpentronsModuleSerialNumber": false, + "mayMountTo": ["cutout12"], + "displayName": "Fixed Trash", + "providesAddressableAreas": { + "cutout12": ["shortFixedTrash"] + }, + "fixtureGroup": {}, + "height": 58 + } + ] +} diff --git a/shared-data/deck/definitions/5/ot2_standard.json b/shared-data/deck/definitions/5/ot2_standard.json new file mode 100644 index 00000000000..0ccc1997c3e --- /dev/null +++ b/shared-data/deck/definitions/5/ot2_standard.json @@ -0,0 +1,409 @@ +{ + "otId": "ot2_standard", + "schemaVersion": 5, + "cornerOffsetFromOrigin": [-115.65, -68.03, 0], + "dimensions": [624.3, 565.2, 0], + "metadata": { + "displayName": "OT-2 Standard Deck", + "tags": ["ot2", "12 slots", "standard"] + }, + "robot": { + "model": "OT-2 Standard" + }, + "locations": { + "addressableAreas": [ + { + "id": "1", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 1", + "compatibleModuleTypes": [ + "magneticModuleType", + "temperatureModuleType", + "heaterShakerModuleType" + ] + }, + { + "id": "2", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 2", + "compatibleModuleTypes": [ + "magneticModuleType", + "temperatureModuleType", + "heaterShakerModuleType" + ] + }, + { + "id": "3", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 3", + "compatibleModuleTypes": [ + "magneticModuleType", + "temperatureModuleType", + "heaterShakerModuleType" + ] + }, + { + "id": "4", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 4", + "compatibleModuleTypes": [ + "magneticModuleType", + "temperatureModuleType", + "heaterShakerModuleType" + ] + }, + { + "id": "5", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 5", + "compatibleModuleTypes": [ + "magneticModuleType", + "temperatureModuleType", + "heaterShakerModuleType" + ] + }, + { + "id": "6", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 6", + "compatibleModuleTypes": [ + "magneticModuleType", + "temperatureModuleType", + "heaterShakerModuleType" + ] + }, + { + "id": "7", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 7", + "compatibleModuleTypes": [ + "magneticModuleType", + "temperatureModuleType", + "thermocyclerModuleType", + "heaterShakerModuleType" + ] + }, + { + "id": "8", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 8", + "compatibleModuleTypes": [ + "magneticModuleType", + "temperatureModuleType", + "heaterShakerModuleType" + ] + }, + { + "id": "9", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 9", + "compatibleModuleTypes": [ + "magneticModuleType", + "temperatureModuleType", + "heaterShakerModuleType" + ] + }, + { + "id": "10", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 10", + "compatibleModuleTypes": [ + "magneticModuleType", + "temperatureModuleType", + "heaterShakerModuleType" + ] + }, + { + "id": "11", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 11", + "compatibleModuleTypes": [ + "magneticModuleType", + "temperatureModuleType", + "heaterShakerModuleType" + ] + }, + { + "id": "12", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot 12", + "compatibleModuleTypes": [] + }, + { + "id": "fixedTrash", + "areaType": "fixedTrash", + "offsetFromCutoutFixture": [29.285, -2.835, 0], + "boundingBox": { + "xDimension": 107.11, + "yDimension": 165.67, + "zDimension": 82 + }, + "displayName": "Slot 12/Fixed Trash", + "ableToDropTips": true + } + ], + "cutouts": [ + { + "id": "cutout1", + "position": [0.0, 0.0, 0.0], + "displayName": "Cutout 1" + }, + { + "id": "cutout2", + "position": [132.5, 0.0, 0.0], + "displayName": "Cutout 2" + }, + { + "id": "cutout3", + "position": [265.0, 0.0, 0.0], + "displayName": "Cutout 3" + }, + { + "id": "cutout4", + "position": [0.0, 90.5, 0.0], + "displayName": "Cutout 4" + }, + { + "id": "cutout5", + "position": [132.5, 90.5, 0.0], + "displayName": "Cutout 5" + }, + { + "id": "cutout6", + "position": [265.0, 90.5, 0.0], + "displayName": "Cutout 6" + }, + { + "id": "cutout7", + "position": [0.0, 181.0, 0.0], + "displayName": "Cutout 7" + }, + { + "id": "cutout8", + "position": [132.5, 181.0, 0.0], + "displayName": "Cutout 8" + }, + { + "id": "cutout9", + "position": [265.0, 181.0, 0.0], + "displayName": "Cutout 9" + }, + { + "id": "cutout10", + "position": [0.0, 271.5, 0.0], + "displayName": "Slot 10" + }, + { + "id": "cutout11", + "position": [132.5, 271.5, 0.0], + "displayName": "Cutout 11" + }, + { + "id": "cutout12", + "position": [265.0, 271.5, 0.0], + "displayName": "Cutout 12" + } + ], + "calibrationPoints": [ + { + "id": "1BLC", + "position": [12.13, 9.0, 0.0], + "displayName": "Slot 1 Bottom Left Cross" + }, + { + "id": "3BRC", + "position": [380.87, 9.0, 0.0], + "displayName": "Slot 3 Bottom Right Cross" + }, + { + "id": "7TLC", + "position": [12.13, 258.0, 0.0], + "displayName": "Slot 7 Top Left Cross" + }, + { + "id": "9TRC", + "position": [380.87, 258.0, 0.0], + "displayName": "Slot 9 Top Right Cross" + }, + { + "id": "10TLC", + "position": [12.13, 348.5, 0.0], + "displayName": "Slot 10 Top Left Cross" + }, + { + "id": "11TRC", + "position": [248.37, 348.5, 0.0], + "displayName": "Slot 11 Top Right Cross" + }, + { + "id": "1BLD", + "position": [12.13, 6.0, 0.0], + "displayName": "Slot 1 Bottom Left Dot" + }, + { + "id": "3BRD", + "position": [380.87, 6.0, 0.0], + "displayName": "Slot 3 Bottom Right Dot" + }, + { + "id": "7TLD", + "position": [12.13, 261.0, 0.0], + "displayName": "Slot 7 Top Left Dot" + }, + { + "id": "9TRD", + "position": [380.87, 261.0, 0.0], + "displayName": "Slot 9 Top Right Dot" + }, + { + "id": "10TLD", + "position": [12.13, 351.5, 0.0], + "displayName": "Slot 10 Top Left Dot" + }, + { + "id": "11TRD", + "position": [248.37, 351.5, 0.0], + "displayName": "Slot 11 Top Right Dot" + } + ], + "legacyFixtures": [ + { + "id": "fixedTrash", + "slot": "12", + "labware": "opentrons_1_trash_1100ml_fixed", + "displayName": "Fixed Trash" + } + ] + }, + "cutoutFixtures": [ + { + "id": "singleStandardSlot", + "expectOpentronsModuleSerialNumber": false, + "mayMountTo": [ + "cutout1", + "cutout2", + "cutout3", + "cutout4", + "cutout5", + "cutout6", + "cutout7", + "cutout8", + "cutout9", + "cutout10", + "cutout11", + "cutout12" + ], + "displayName": "Standard Slot", + "providesAddressableAreas": { + "cutout1": ["1"], + "cutout2": ["2"], + "cutout3": ["3"], + "cutout4": ["4"], + "cutout5": ["5"], + "cutout6": ["6"], + "cutout7": ["7"], + "cutout8": ["8"], + "cutout9": ["9"], + "cutout10": ["10"], + "cutout11": ["11"], + "cutout12": ["12"] + }, + "fixtureGroup": {}, + "height": 0 + }, + { + "id": "fixedTrashSlot", + "expectOpentronsModuleSerialNumber": false, + "mayMountTo": ["cutout12"], + "displayName": "Fixed Trash", + "providesAddressableAreas": { + "cutout12": ["fixedTrash"] + }, + "fixtureGroup": {}, + "height": 82 + } + ] +} diff --git a/shared-data/deck/definitions/5/ot3_standard.json b/shared-data/deck/definitions/5/ot3_standard.json new file mode 100644 index 00000000000..85dcbf64792 --- /dev/null +++ b/shared-data/deck/definitions/5/ot3_standard.json @@ -0,0 +1,1042 @@ +{ + "otId": "ot3_standard", + "schemaVersion": 5, + "cornerOffsetFromOrigin": [-204.31, -76.59, 0], + "dimensions": [854.995, 581.74, 0], + "metadata": { + "displayName": "OT-3 Standard Deck", + "tags": ["ot3", "12 slots", "standard"] + }, + "robot": { + "model": "OT-3 Standard" + }, + "locations": { + "addressableAreas": [ + { + "id": "D1", + "areaType": "slot", + "matingSurfaceUnitVector": [-1, 1, -1], + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot D1" + }, + { + "id": "D2", + "areaType": "slot", + "matingSurfaceUnitVector": [-1, 1, -1], + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot D2" + }, + { + "id": "D3", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot D3" + }, + { + "id": "C1", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot C1" + }, + { + "id": "C2", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot C2" + }, + { + "id": "C3", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot C3" + }, + { + "id": "B1", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot B1" + }, + { + "id": "B2", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot B2" + }, + { + "id": "B3", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot B3" + }, + { + "id": "A1", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot A1" + }, + { + "id": "A2", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot A2", + "compatibleModuleTypes": [] + }, + { + "id": "A3", + "areaType": "slot", + "offsetFromCutoutFixture": [0.0, 0.0, 0.0], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot A3", + "compatibleModuleTypes": [] + }, + { + "id": "A4", + "areaType": "stagingSlot", + "offsetFromCutoutFixture": [164.0, 0.0, 14.5], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot A4", + "compatibleModuleTypes": [] + }, + { + "id": "B4", + "areaType": "stagingSlot", + "offsetFromCutoutFixture": [164.0, 0.0, 14.5], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot B4", + "compatibleModuleTypes": [] + }, + { + "id": "C4", + "areaType": "stagingSlot", + "offsetFromCutoutFixture": [164.0, 0.0, 14.5], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot C4", + "compatibleModuleTypes": [] + }, + { + "id": "D4", + "areaType": "stagingSlot", + "offsetFromCutoutFixture": [164.0, 0.0, 14.5], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Slot D4", + "compatibleModuleTypes": [] + }, + { + "id": "movableTrashD1", + "areaType": "movableTrash", + "offsetFromCutoutFixture": [-90.25, 4, 0.0], + "boundingBox": { + "xDimension": 225, + "yDimension": 78, + "zDimension": 40 + }, + "displayName": "Trash Bin in D1", + "ableToDropTips": true + }, + { + "id": "movableTrashC1", + "areaType": "movableTrash", + "offsetFromCutoutFixture": [-90.25, 4, 0.0], + "boundingBox": { + "xDimension": 225, + "yDimension": 78, + "zDimension": 40 + }, + "displayName": "Trash Bin in C1", + "ableToDropTips": true + }, + { + "id": "movableTrashB1", + "areaType": "movableTrash", + "offsetFromCutoutFixture": [-90.25, 4, 0.0], + "boundingBox": { + "xDimension": 225, + "yDimension": 78, + "zDimension": 40 + }, + "displayName": "Trash Bin in B1", + "ableToDropTips": true + }, + { + "id": "movableTrashA1", + "areaType": "movableTrash", + "offsetFromCutoutFixture": [-90.25, 4, 0.0], + "boundingBox": { + "xDimension": 225, + "yDimension": 78, + "zDimension": 40 + }, + "displayName": "Trash Bin in A1", + "ableToDropTips": true + }, + { + "id": "movableTrashD3", + "areaType": "movableTrash", + "offsetFromCutoutFixture": [-6.25, 4, 0.0], + "boundingBox": { + "xDimension": 225, + "yDimension": 78, + "zDimension": 40 + }, + "displayName": "Trash Bin in D3", + "ableToDropTips": true + }, + { + "id": "movableTrashC3", + "areaType": "movableTrash", + "offsetFromCutoutFixture": [-6.25, 4, 0.0], + "boundingBox": { + "xDimension": 225, + "yDimension": 78, + "zDimension": 40 + }, + "displayName": "Trash Bin in C3", + "ableToDropTips": true + }, + { + "id": "movableTrashB3", + "areaType": "movableTrash", + "offsetFromCutoutFixture": [-6.25, 4, 0.0], + "boundingBox": { + "xDimension": 225, + "yDimension": 78, + "zDimension": 40 + }, + "displayName": "Trash Bin in B3", + "ableToDropTips": true + }, + { + "id": "movableTrashA3", + "areaType": "movableTrash", + "offsetFromCutoutFixture": [-6.25, 4, 0.0], + "boundingBox": { + "xDimension": 225, + "yDimension": 78, + "zDimension": 40 + }, + "displayName": "Trash Bin in A3", + "ableToDropTips": true + }, + { + "id": "1ChannelWasteChute", + "areaType": "wasteChute", + "offsetFromCutoutFixture": [64, 36, 114.5], + "boundingBox": { + "xDimension": 0, + "yDimension": 0, + "zDimension": 0 + }, + "displayName": "Waste Chute", + "ableToDropTips": true + }, + { + "id": "8ChannelWasteChute", + "areaType": "wasteChute", + "offsetFromCutoutFixture": [64, -27, 114.5], + "boundingBox": { + "xDimension": 0, + "yDimension": 63, + "zDimension": 0 + }, + "displayName": "Waste Chute", + "ableToDropTips": true + }, + { + "id": "96ChannelWasteChute", + "areaType": "wasteChute", + "offsetFromCutoutFixture": [14.445, -20.915, 114.5], + "boundingBox": { + "xDimension": 99, + "yDimension": 63, + "zDimension": 0 + }, + "displayName": "Waste Chute", + "ableToDropTips": true + }, + { + "id": "gripperWasteChute", + "areaType": "wasteChute", + "offsetFromCutoutFixture": [64, 29, 136.5], + "boundingBox": { + "xDimension": 0, + "yDimension": 0, + "zDimension": 0 + }, + "displayName": "Waste Chute", + "ableToDropLabware": true + }, + { + "id": "thermocyclerModuleV2", + "areaType": "thermocycler", + "offsetFromCutoutFixture": [-20.005, 67.96, 10.96], + "matingSurfaceUnitVector": [-1, 1, -1], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Thermocycler Module Slot" + }, + { + "id": "heaterShakerV1D1", + "areaType": "heaterShaker", + "offsetFromCutoutFixture": [0, 0, 18.95], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Heater Shaker in D1" + }, + { + "id": "heaterShakerV1C1", + "areaType": "heaterShaker", + "offsetFromCutoutFixture": [0.0, 0.0, 18.95], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Heater Shaker in C1" + }, + { + "id": "heaterShakerV1B1", + "areaType": "heaterShaker", + "offsetFromCutoutFixture": [0.0, 0.0, 18.95], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Heater Shaker in B1" + }, + { + "id": "heaterShakerV1A1", + "areaType": "heaterShaker", + "offsetFromCutoutFixture": [0.0, 0.0, 18.95], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Heater Shaker in A1" + }, + { + "id": "heaterShakerV1D3", + "areaType": "heaterShaker", + "offsetFromCutoutFixture": [0.0, 0.0, 18.95], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Heater Shaker in D3" + }, + { + "id": "heaterShakerV1C3", + "areaType": "heaterShaker", + "offsetFromCutoutFixture": [0.0, 0.0, 18.95], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Heater Shaker in C3" + }, + { + "id": "heaterShakerV1B3", + "areaType": "heaterShaker", + "offsetFromCutoutFixture": [0.0, 0.0, 18.95], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Heater Shaker in B3" + }, + { + "id": "heaterShakerV1A3", + "areaType": "heaterShaker", + "offsetFromCutoutFixture": [0.0, 0.0, 18.95], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Heater Shaker in A3" + }, + { + "id": "temperatureModuleV2D1", + "areaType": "temperatureModule", + "offsetFromCutoutFixture": [0.0, 0.0, 9.0], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Temperature Module in D1" + }, + { + "id": "temperatureModuleV2C1", + "areaType": "temperatureModule", + "offsetFromCutoutFixture": [0.0, 0.0, 9.0], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Temperature Module in C1" + }, + { + "id": "temperatureModuleV2B1", + "areaType": "temperatureModule", + "offsetFromCutoutFixture": [0.0, 0.0, 9.0], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Temperature Module in B1" + }, + { + "id": "temperatureModuleV2A1", + "areaType": "temperatureModule", + "offsetFromCutoutFixture": [0.0, 0.0, 9.0], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Temperature Module in A1" + }, + { + "id": "temperatureModuleV2D3", + "areaType": "temperatureModule", + "offsetFromCutoutFixture": [0.0, 0.0, 9.0], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Temperature Module in D3" + }, + { + "id": "temperatureModuleV2C3", + "areaType": "temperatureModule", + "offsetFromCutoutFixture": [0.0, 0.0, 9.0], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Temperature Module in C3" + }, + { + "id": "temperatureModuleV2B3", + "areaType": "temperatureModule", + "offsetFromCutoutFixture": [0.0, 0.0, 9.0], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Temperature Module in B3" + }, + { + "id": "temperatureModuleV2A3", + "areaType": "temperatureModule", + "offsetFromCutoutFixture": [0.0, 0.0, 9.0], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Temperature Module in A3" + }, + { + "id": "magneticBlockV1D1", + "areaType": "magneticBlock", + "offsetFromCutoutFixture": [0.0, 0.0, 38], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Magnetic Block in D1" + }, + { + "id": "magneticBlockV1C1", + "areaType": "magneticBlock", + "offsetFromCutoutFixture": [0.0, 0.0, 38], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Magnetic Block in C1" + }, + { + "id": "magneticBlockV1B1", + "areaType": "magneticBlock", + "offsetFromCutoutFixture": [0.0, 0.0, 38], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Magnetic Block in B1" + }, + { + "id": "magneticBlockV1A1", + "areaType": "magneticBlock", + "offsetFromCutoutFixture": [0.0, 0.0, 38], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Magnetic Block in A1" + }, + { + "id": "magneticBlockV1D2", + "areaType": "magneticBlock", + "offsetFromCutoutFixture": [0.0, 0.0, 38], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Magnetic Block in D2" + }, + { + "id": "magneticBlockV1C2", + "areaType": "magneticBlock", + "offsetFromCutoutFixture": [0.0, 0.0, 38], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Magnetic Block in C2" + }, + { + "id": "magneticBlockV1B2", + "areaType": "magneticBlock", + "offsetFromCutoutFixture": [0.0, 0.0, 38], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Magnetic Block in B2" + }, + { + "id": "magneticBlockV1A2", + "areaType": "magneticBlock", + "offsetFromCutoutFixture": [0.0, 0.0, 38], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Magnetic Block in A2" + }, + { + "id": "magneticBlockV1D3", + "areaType": "magneticBlock", + "offsetFromCutoutFixture": [0.0, 0.0, 38], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Magnetic Block in D3" + }, + { + "id": "magneticBlockV1C3", + "areaType": "magneticBlock", + "offsetFromCutoutFixture": [0.0, 0.0, 38], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Magnetic Block in C3" + }, + { + "id": "magneticBlockV1B3", + "areaType": "magneticBlock", + "offsetFromCutoutFixture": [0.0, 0.0, 38], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Magnetic Block in B3" + }, + { + "id": "magneticBlockV1A3", + "areaType": "magneticBlock", + "offsetFromCutoutFixture": [0.0, 0.0, 38], + "boundingBox": { + "xDimension": 128.0, + "yDimension": 86.0, + "zDimension": 0 + }, + "displayName": "Magnetic Block in A3" + } + ], + "cutouts": [ + { + "id": "cutoutD1", + "position": [0.0, 0.0, 0.0], + "displayName": "Cutout D1" + }, + { + "id": "cutoutD2", + "position": [164.0, 0.0, 0.0], + "displayName": "Cutout D2" + }, + { + "id": "cutoutD3", + "position": [328.0, 0.0, 0.0], + "displayName": "Cutout D3" + }, + { + "id": "cutoutC1", + "position": [0.0, 107, 0.0], + "displayName": "Cutout C1" + }, + { + "id": "cutoutC2", + "position": [164.0, 107, 0.0], + "displayName": "Cutout C2" + }, + { + "id": "cutoutC3", + "position": [328.0, 107, 0.0], + "displayName": "Cutout C3" + }, + { + "id": "cutoutB1", + "position": [0.0, 214.0, 0.0], + "displayName": "Cutout B1" + }, + { + "id": "cutoutB2", + "position": [164.0, 214.0, 0.0], + "displayName": "Cutout B2" + }, + { + "id": "cutoutB3", + "position": [328.0, 214.0, 0.0], + "displayName": "Cutout B3" + }, + { + "id": "cutoutA1", + "position": [0.0, 321.0, 0.0], + "displayName": "Cutout A1" + }, + { + "id": "cutoutA2", + "position": [164.0, 321.0, 0.0], + "displayName": "Cutout A2" + }, + { + "id": "cutoutA3", + "position": [328.0, 321.0, 0.0], + "displayName": "Cutout A3" + } + ], + "calibrationPoints": [], + "legacyFixtures": [ + { + "id": "fixedTrash", + "slot": "A3", + "labware": "opentrons_1_trash_3200ml_fixed", + "displayName": "Fixed Trash" + } + ] + }, + "cutoutFixtures": [ + { + "id": "singleLeftSlot", + "expectOpentronsModuleSerialNumber": false, + "mayMountTo": ["cutoutD1", "cutoutC1", "cutoutB1", "cutoutA1"], + "displayName": "Standard Slot Left", + "providesAddressableAreas": { + "cutoutD1": ["D1"], + "cutoutC1": ["C1"], + "cutoutB1": ["B1"], + "cutoutA1": ["A1"] + }, + "fixtureGroup": {}, + "height": 0 + }, + { + "id": "singleCenterSlot", + "expectOpentronsModuleSerialNumber": false, + "mayMountTo": ["cutoutD2", "cutoutC2", "cutoutB2", "cutoutA2"], + "displayName": "Standard Slot Center", + "providesAddressableAreas": { + "cutoutD2": ["D2"], + "cutoutC2": ["C2"], + "cutoutB2": ["B2"], + "cutoutA2": ["A2"] + }, + "fixtureGroup": {}, + "height": 0 + }, + { + "id": "singleRightSlot", + "expectOpentronsModuleSerialNumber": false, + "mayMountTo": ["cutoutD3", "cutoutC3", "cutoutB3", "cutoutA3"], + "displayName": "Standard Slot Right", + "providesAddressableAreas": { + "cutoutD3": ["D3"], + "cutoutC3": ["C3"], + "cutoutB3": ["B3"], + "cutoutA3": ["A3"] + }, + "fixtureGroup": {}, + "height": 0 + }, + { + "id": "stagingAreaRightSlot", + "expectOpentronsModuleSerialNumber": false, + "mayMountTo": ["cutoutD3", "cutoutC3", "cutoutB3", "cutoutA3"], + "displayName": "Staging Area Slot", + "providesAddressableAreas": { + "cutoutD3": ["D3", "D4"], + "cutoutC3": ["C3", "C4"], + "cutoutB3": ["B3", "B4"], + "cutoutA3": ["A3", "A4"] + }, + "fixtureGroup": {}, + "height": 0 + }, + { + "id": "trashBinAdapter", + "expectOpentronsModuleSerialNumber": false, + "mayMountTo": [ + "cutoutD1", + "cutoutC1", + "cutoutB1", + "cutoutA1", + "cutoutD3", + "cutoutC3", + "cutoutB3", + "cutoutA3" + ], + "displayName": "Slot With Movable Trash", + "providesAddressableAreas": { + "cutoutD1": ["movableTrashD1"], + "cutoutC1": ["movableTrashC1"], + "cutoutB1": ["movableTrashB1"], + "cutoutA1": ["movableTrashA1"], + "cutoutD3": ["movableTrashD3"], + "cutoutC3": ["movableTrashC3"], + "cutoutB3": ["movableTrashB3"], + "cutoutA3": ["movableTrashA3"] + }, + "fixtureGroup": {}, + "height": 40 + }, + { + "id": "wasteChuteRightAdapterCovered", + "expectOpentronsModuleSerialNumber": false, + "mayMountTo": ["cutoutD3"], + "displayName": "Waste Chute Adapter for 1 or 8 Channel Pipettes", + "providesAddressableAreas": { + "cutoutD3": ["1ChannelWasteChute", "8ChannelWasteChute"] + }, + "fixtureGroup": {}, + "height": 124.5 + }, + { + "id": "wasteChuteRightAdapterNoCover", + "expectOpentronsModuleSerialNumber": false, + "mayMountTo": ["cutoutD3"], + "displayName": "Waste Chute Adapter for 96 Channel Pipette or Gripper", + "providesAddressableAreas": { + "cutoutD3": [ + "1ChannelWasteChute", + "8ChannelWasteChute", + "96ChannelWasteChute", + "gripperWasteChute" + ] + }, + "fixtureGroup": {}, + "height": 124.5 + }, + { + "id": "stagingAreaSlotWithWasteChuteRightAdapterCovered", + "expectOpentronsModuleSerialNumber": false, + "mayMountTo": ["cutoutD3"], + "displayName": "Staging Slot With Waste Chute Adapter for 96 Channel Pipette or Gripper", + "providesAddressableAreas": { + "cutoutD3": ["1ChannelWasteChute", "8ChannelWasteChute", "D4"] + }, + "fixtureGroup": {}, + "height": 124.5 + }, + { + "id": "stagingAreaSlotWithWasteChuteRightAdapterNoCover", + "expectOpentronsModuleSerialNumber": false, + "mayMountTo": ["cutoutD3"], + "displayName": "Staging Slot With Waste Chute Adapter and Staging Area Slot", + "providesAddressableAreas": { + "cutoutD3": [ + "1ChannelWasteChute", + "8ChannelWasteChute", + "96ChannelWasteChute", + "gripperWasteChute", + "D4" + ] + }, + "fixtureGroup": {}, + "height": 124.5 + }, + { + "id": "thermocyclerModuleV2Rear", + "expectOpentronsModuleSerialNumber": true, + "mayMountTo": ["cutoutA1"], + "displayName": "Rear Slot portion of the Thermocycler Moduler", + "providesAddressableAreas": { + "cutoutA1": [] + }, + "fixtureGroup": { + "cutoutA1": [ + { + "cutoutA1": "thermocyclerModuleV2Rear", + "cutoutB1": "thermocyclerModuleV2Front" + } + ] + }, + "height": 72.35 + }, + { + "id": "thermocyclerModuleV2Front", + "expectOpentronsModuleSerialNumber": true, + "mayMountTo": ["cutoutB1"], + "displayName": "Front Slot portion of the Thermocycler Moduler", + "providesAddressableAreas": { + "cutoutB1": ["thermocyclerModuleV2"] + }, + "fixtureGroup": { + "cutoutB1": [ + { + "cutoutA1": "thermocyclerModuleV2Rear", + "cutoutB1": "thermocyclerModuleV2Front" + } + ] + }, + "height": 72.35 + }, + { + "id": "heaterShakerModuleV1", + "expectOpentronsModuleSerialNumber": true, + "mayMountTo": [ + "cutoutD1", + "cutoutC1", + "cutoutB1", + "cutoutA1", + "cutoutD3", + "cutoutC3", + "cutoutB3", + "cutoutA3" + ], + "displayName": "Slot With a Heater Shaker", + "providesAddressableAreas": { + "cutoutD1": ["heaterShakerV1D1"], + "cutoutC1": ["heaterShakerV1C1"], + "cutoutB1": ["heaterShakerV1B1"], + "cutoutA1": ["heaterShakerV1A1"], + "cutoutD3": ["heaterShakerV1D3"], + "cutoutC3": ["heaterShakerV1C3"], + "cutoutB3": ["heaterShakerV1B3"], + "cutoutA3": ["heaterShakerV1A3"] + }, + "fixtureGroup": {}, + "height": 18.95 + }, + { + "id": "temperatureModuleV2", + "expectOpentronsModuleSerialNumber": true, + "mayMountTo": [ + "cutoutD1", + "cutoutC1", + "cutoutB1", + "cutoutA1", + "cutoutD3", + "cutoutC3", + "cutoutB3", + "cutoutA3" + ], + "displayName": "Slot With a Temperature Module", + "providesAddressableAreas": { + "cutoutD1": ["temperatureModuleV2D1"], + "cutoutC1": ["temperatureModuleV2C1"], + "cutoutB1": ["temperatureModuleV2B1"], + "cutoutA1": ["temperatureModuleV2A1"], + "cutoutD3": ["temperatureModuleV2D3"], + "cutoutC3": ["temperatureModuleV2C3"], + "cutoutB3": ["temperatureModuleV2B3"], + "cutoutA3": ["temperatureModuleV2A3"] + }, + "fixtureGroup": {}, + "height": 9.0 + }, + { + "id": "magneticBlockV1", + "expectOpentronsModuleSerialNumber": false, + "mayMountTo": [ + "cutoutD1", + "cutoutC1", + "cutoutB1", + "cutoutA1", + "cutoutD2", + "cutoutC2", + "cutoutB2", + "cutoutA2", + "cutoutD3", + "cutoutC3", + "cutoutB3", + "cutoutA3" + ], + "displayName": "Slot With a Magnetic Block", + "providesAddressableAreas": { + "cutoutD1": ["magneticBlockV1D1"], + "cutoutC1": ["magneticBlockV1C1"], + "cutoutB1": ["magneticBlockV1B1"], + "cutoutA1": ["magneticBlockV1A1"], + "cutoutD2": ["magneticBlockV1D2"], + "cutoutC2": ["magneticBlockV1C2"], + "cutoutB2": ["magneticBlockV1B2"], + "cutoutA2": ["magneticBlockV1A2"], + "cutoutD3": ["magneticBlockV1D3"], + "cutoutC3": ["magneticBlockV1C3"], + "cutoutB3": ["magneticBlockV1B3"], + "cutoutA3": ["magneticBlockV1A3"] + }, + "fixtureGroup": {}, + "height": 38.0 + }, + { + "id": "stagingAreaSlotWithMagneticBlockV1", + "expectOpentronsModuleSerialNumber": false, + "mayMountTo": ["cutoutD3", "cutoutC3", "cutoutB3", "cutoutA3"], + "displayName": "Fixture that provides a Magnetic Block and a Staging Area Slot", + "providesAddressableAreas": { + "cutoutD3": ["magneticBlockV1D3", "D4"], + "cutoutC3": ["magneticBlockV1C3", "C4"], + "cutoutB3": ["magneticBlockV1B3", "B4"], + "cutoutA3": ["magneticBlockV1A3", "A4"] + }, + "fixtureGroup": {}, + "height": 38.0 + } + ], + "gripperOffsets": { + "default": { + "pickUpOffset": { + "x": 0, + "y": 0, + "z": 0 + }, + "dropOffset": { + "x": 0, + "y": 0, + "z": -0.75 + } + } + } +} diff --git a/shared-data/deck/index.ts b/shared-data/deck/index.ts index e308d7a17ad..7d68bdeebd9 100644 --- a/shared-data/deck/index.ts +++ b/shared-data/deck/index.ts @@ -8,11 +8,16 @@ import ot2StandardDeckV4 from './definitions/4/ot2_standard.json' import ot2ShortFixedTrashDeckV4 from './definitions/4/ot2_short_trash.json' import ot3StandardDeckV4 from './definitions/4/ot3_standard.json' +// v5 deck defs +import ot2StandardDeckV5 from './definitions/5/ot2_standard.json' +import ot2ShortFixedTrashDeckV5 from './definitions/5/ot2_short_trash.json' +import ot3StandardDeckV5 from './definitions/5/ot3_standard.json' + import deckExample from './fixtures/3/deckExample.json' import type { DeckDefinition } from '../js/types' -export * from './types/schemaV4' +export * from './types/schemaV5' export { ot2StandardDeckV3, @@ -21,13 +26,16 @@ export { ot2StandardDeckV4, ot2ShortFixedTrashDeckV4, ot3StandardDeckV4, + ot2StandardDeckV5, + ot2ShortFixedTrashDeckV5, + ot3StandardDeckV5, deckExample, } const latestDeckDefinitions = { - ot2StandardDeckV4, - ot2ShortFixedTrashDeckV4, - ot3StandardDeckV4, + ot2StandardDeckV5, + ot2ShortFixedTrashDeckV5, + ot3StandardDeckV5, } export function getDeckDefinitions(): Record { diff --git a/shared-data/deck/schemas/5.json b/shared-data/deck/schemas/5.json new file mode 100644 index 00000000000..da77152da13 --- /dev/null +++ b/shared-data/deck/schemas/5.json @@ -0,0 +1,338 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "opentronsDeckSchemaV5", + "definitions": { + "positiveNumber": { + "type": "number", + "minimum": 0 + }, + "xyzArray": { + "type": "array", + "description": "Array of 3 numbers, [x, y, z]", + "items": { "type": "number" }, + "minItems": 3, + "maxItems": 3 + }, + "coordinates": { + "type": "object", + "additionalProperties": false, + "required": ["x", "y", "z"], + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + }, + "z": { + "type": "number" + } + } + }, + "unitVector": { + "type": "array", + "description": "Array of 3 unit directions, [x, y, z]", + "items": { + "type": "number", + "enum": [1, -1] + }, + "minItems": 3, + "maxItems": 3 + }, + "boundingBox": { + "type": "object", + "required": ["xDimension", "yDimension", "zDimension"], + "properties": { + "xDimension": { "$ref": "#/definitions/positiveNumber" }, + "yDimension": { "$ref": "#/definitions/positiveNumber" }, + "zDimension": { "$ref": "#/definitions/positiveNumber" } + } + } + }, + "description": "Deck specifications, where x,y,z (0,0,0) is at front the bottom left corner.", + "type": "object", + "additionalProperties": false, + "required": [ + "otId", + "schemaVersion", + "cornerOffsetFromOrigin", + "dimensions", + "metadata", + "robot", + "locations", + "cutoutFixtures" + ], + "properties": { + "otId": { + "description": "Unique internal ID generated using UUID", + "type": "string" + }, + "schemaVersion": { + "description": "Schema version of a deck is a single integer", + "enum": [5] + }, + "cornerOffsetFromOrigin": { + "$ref": "#/definitions/xyzArray", + "description": "Position of left-front-bottom corner of entire deck to robot coordinate system origin" + }, + "dimensions": { + "$ref": "#/definitions/xyzArray", + "description": "Outer dimensions of a deck bounding box" + }, + "metadata": { + "description": "Optional metadata about the Deck", + "type": "object", + "properties": { + "displayName": { + "description": "A short, human-readable name for the deck", + "type": "string" + }, + "tags": { + "description": "Tags to be used in searching for this deck", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "robot": { + "type": "object", + "required": ["model"], + "properties": { + "model": { + "description": "Model of the robot", + "type": "string", + "enum": ["OT-2 Standard", "OT-3 Standard"] + } + } + }, + "locations": { + "type": "object", + "required": [ + "addressableAreas", + "calibrationPoints", + "cutouts", + "legacyFixtures" + ], + "properties": { + "addressableAreas": { + "type": "array", + "items": { + "type": "object", + "description": "An addressable area is a named area in 3D space that the robot can interact with--for example, as a place to drop tips, or hold a labware.", + "required": [ + "id", + "areaType", + "offsetFromCutoutFixture", + "boundingBox", + "displayName" + ], + "properties": { + "id": { + "description": "Unique identifier for slot", + "type": "string" + }, + "areaType": { + "description": "The type of addressable area, defining allowed behavior.", + "type": "string", + "enum": [ + "slot", + "stagingSlot", + "movableTrash", + "fixedTrash", + "wasteChute" + ] + }, + "offsetFromCutoutFixture": { + "$ref": "#/definitions/xyzArray", + "description": "The offset from the origin of the cutout fixture that's providing this addressable area (which is currently identical to the position of the underlying cutout), to the -x, -y, -z corner of this addressable area's bounding box." + }, + "matingSurfaceUnitVector": { + "$ref": "#/definitions/unitVector", + "description": "An optional diagonal direction of force, defined by spring location, which governs the mating surface of objects placed in this addressable area. Meant to be used when this addressable area is a slot." + }, + "boundingBox": { + "description": "The active area (both pipettes can reach) of this addressable area.", + "$ref": "#/definitions/boundingBox" + }, + "displayName": { + "description": "A human-readable nickname for this area e.g. \"Slot A1\" or \"Trash Bin in A1\"", + "type": "string" + }, + "compatibleModuleTypes": { + "description": "OT-2 Only parameter. An array of module types that can be placed in this area. The module type names can be found in the moduleType field of a module definition.", + "type": "array", + "items": { + "type": "string" + } + }, + "ableToDropTips": { + "description": "Whether tips are allowed to be dropped into this area. If `true`, the top-center of the `boundingBox` should be a good location for the bottom-center of all the tips when they're dropped.", + "type": "boolean" + }, + "ableToDropLabware": { + "description": "Whether labware is allowed to be dropped (different from being placed) into this area. If `true`, the top-center of the `boundingBox` should be a good location for the bottom-center of the labware when it's dropped.", + "type": "boolean" + } + } + } + }, + "calibrationPoints": { + "type": "array", + "description": "Key points for deck calibration", + "items": { + "type": "object", + "required": ["id", "position", "displayName"], + "properties": { + "id": { + "description": "Unique identifier for calibration point", + "type": "string" + }, + "position": { + "$ref": "#/definitions/xyzArray" + }, + "displayName": { + "description": "An optional human-readable nickname for this point Eg \"Slot 3 Cross\" or \"Slot 1 Dot\"", + "type": "string" + } + } + } + }, + "cutouts": { + "type": "array", + "description": "The machined cutout slots on the deck surface.", + "items": { + "type": "object", + "required": ["id", "position", "displayName"], + "properties": { + "id": { + "description": "Unique identifier for the cutout", + "type": "string" + }, + "position": { + "description": "Absolute position of the cutout", + "$ref": "#/definitions/xyzArray" + }, + "displayName": { + "description": "An optional human-readable nickname for this cutout e.g. \"Cutout A1\"", + "type": "string" + } + } + } + }, + "legacyFixtures": { + "type": "array", + "description": "Fixed position objects on the deck.", + "items": { + "type": "object", + "required": ["id", "displayName"], + "properties": { + "id": { + "description": "Unique identifier for fixed object", + "type": "string" + }, + "labware": { + "description": "Valid labware loadName for fixed object", + "type": "string" + }, + "slot": { + "description": "Slot location of the fixed object", + "type": "string" + }, + "displayName": { + "description": "An optional human-readable nickname for this fixture Eg \"Tall Fixed Trash\" or \"Short Fixed Trash\"", + "type": "string" + } + } + } + } + } + }, + "cutoutFixtures": { + "type": "array", + "items": { + "description": "A cutout fixture is a physical thing that can be mounted onto one of the deck cutouts.", + "type": "object", + "required": [ + "id", + "expectOpentronsModuleSerialNumber", + "mayMountTo", + "displayName", + "providesAddressableAreas", + "fixtureGroup", + "height" + ], + "properties": { + "id": { + "description": "Unique identifier for the cutout fixture.", + "type": "string" + }, + "expectOpentronsModuleSerialNumber": { + "description": "Determines whether or not a fixture expects a serial number for a connected Opentrons Module.", + "type": "boolean" + }, + "mayMountTo": { + "description": "A list of compatible cutouts this fixture may be mounted to. These must match `id`s in `cutouts`.", + "type": "array", + "items": { + "type": "string" + } + }, + "displayName": { + "description": "A human-readable nickname for this area e.g. \"Standard Right Slot\" or \"Slot With Movable Trash\"", + "type": "string" + }, + "providesAddressableAreas": { + "description": "The addressable areas that this cutout fixture provides, when it's mounted. It can provide different addressable areas depending on where it's mounted. Keys must match values from this object's `mayMountTo`. Values must match `id`s from `addressableAreas`.", + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "fixtureGroup": { + "description": "The map of fixtures that must exist in the deck configuration if this fixture exists, with the mounting location acting as a key to determine the location of the rest of the group.", + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "height": { + "description": "The vertical distance (mm) from the cutout fixture's origin to its tallest physical feature that an instrument could collide with.", + "type": "number" + } + } + } + }, + "gripperOffsets": { + "type": "object", + "description": "Offsets to be added when calculating the coordinates a gripper should go to when picking up or dropping a labware on this deck.", + "properties": { + "default": { + "type": "object", + "properties": { + "pickUpOffset": { + "$ref": "#/definitions/coordinates", + "description": "Offset added to calculate pick-up coordinates of a labware placed on this deck." + }, + "dropOffset": { + "$ref": "#/definitions/coordinates", + "description": "Offset added to calculate drop coordinates of a labware placed on this deck." + } + }, + "required": ["pickUpOffset", "dropOffset"] + } + }, + "required": ["default"] + } + } +} diff --git a/shared-data/deck/types/schemaV5.ts b/shared-data/deck/types/schemaV5.ts new file mode 100644 index 00000000000..e763b893bde --- /dev/null +++ b/shared-data/deck/types/schemaV5.ts @@ -0,0 +1,141 @@ +export type FlexAddressableAreaName = + | 'A1' + | 'B1' + | 'C1' + | 'D1' + | 'A2' + | 'B2' + | 'C2' + | 'D2' + | 'A3' + | 'B3' + | 'C3' + | 'D3' + | 'A4' + | 'B4' + | 'C4' + | 'D4' + | 'movableTrashA1' + | 'movableTrashB1' + | 'movableTrashC1' + | 'movableTrashD1' + | 'movableTrashA3' + | 'movableTrashB3' + | 'movableTrashC3' + | 'movableTrashD3' + | '1ChannelWasteChute' + | '8ChannelWasteChute' + | '96ChannelWasteChute' + | 'gripperWasteChute' + | 'thermocyclerModuleV2' + | 'heaterShakerV1A1' + | 'heaterShakerV1B1' + | 'heaterShakerV1C1' + | 'heaterShakerV1D1' + | 'heaterShakerV1A3' + | 'heaterShakerV1B3' + | 'heaterShakerV1C3' + | 'heaterShakerV1D3' + | 'temperatureModuleV2A1' + | 'temperatureModuleV2B1' + | 'temperatureModuleV2C1' + | 'temperatureModuleV2D1' + | 'temperatureModuleV2A3' + | 'temperatureModuleV2B3' + | 'temperatureModuleV2C3' + | 'temperatureModuleV2D3' + | 'magneticBlockV1A1' + | 'magneticBlockV1B1' + | 'magneticBlockV1C1' + | 'magneticBlockV1D1' + | 'magneticBlockV1A2' + | 'magneticBlockV1B2' + | 'magneticBlockV1C2' + | 'magneticBlockV1D2' + | 'magneticBlockV1A3' + | 'magneticBlockV1B3' + | 'magneticBlockV1C3' + | 'magneticBlockV1D3' + +export type OT2AddressableAreaName = + | '1' + | '2' + | '3' + | '4' + | '5' + | '6' + | '7' + | '8' + | '9' + | '10' + | '11' + | '12' + | 'fixedTrash' + +export type AddressableAreaName = + | FlexAddressableAreaName + | OT2AddressableAreaName + +export type CutoutId = + | 'cutoutD1' + | 'cutoutD2' + | 'cutoutD3' + | 'cutoutC1' + | 'cutoutC2' + | 'cutoutC3' + | 'cutoutB1' + | 'cutoutB2' + | 'cutoutB3' + | 'cutoutA1' + | 'cutoutA2' + | 'cutoutA3' + +export type OT2CutoutId = + | 'cutout1' + | 'cutout2' + | 'cutout3' + | 'cutout4' + | 'cutout5' + | 'cutout6' + | 'cutout7' + | 'cutout8' + | 'cutout9' + | 'cutout10' + | 'cutout11' + | 'cutout12' + +export type SingleSlotCutoutFixtureId = + | 'singleLeftSlot' + | 'singleCenterSlot' + | 'singleRightSlot' + +export type StagingAreaRightSlotFixtureId = 'stagingAreaRightSlot' + +export type TrashBinAdapterCutoutFixtureId = 'trashBinAdapter' + +export type WasteChuteCutoutFixtureId = + | 'wasteChuteRightAdapterCovered' + | 'wasteChuteRightAdapterNoCover' + | 'stagingAreaSlotWithWasteChuteRightAdapterCovered' + | 'stagingAreaSlotWithWasteChuteRightAdapterNoCover' + +export type FlexModuleCutoutFixtureId = + | 'heaterShakerModuleV1' + | 'temperatureModuleV2' + | 'magneticBlockV1' + | 'stagingAreaSlotWithMagneticBlockV1' + | 'thermocyclerModuleV2Rear' + | 'thermocyclerModuleV2Front' + +export type OT2SingleStandardSlot = 'singleStandardSlot' + +export type OT2FixedTrashSlot = 'fixedTrashSlot' + +export type CutoutFixtureId = + | SingleSlotCutoutFixtureId + | StagingAreaRightSlotFixtureId + | TrashBinAdapterCutoutFixtureId + | WasteChuteCutoutFixtureId + | FlexModuleCutoutFixtureId + | OT2SingleStandardSlot + | OT2FixedTrashSlot diff --git a/shared-data/js/__tests__/pipettes.test.ts b/shared-data/js/__tests__/pipettes.test.ts index 6eae38eba66..14b3b417a8f 100644 --- a/shared-data/js/__tests__/pipettes.test.ts +++ b/shared-data/js/__tests__/pipettes.test.ts @@ -63,7 +63,7 @@ describe('pipette data accessors', () => { }) describe('getPipetteSpecsV2', () => { - it('returns the correct info for p1000_single_flex', () => { + it('returns the correct info for p1000_single_flex which should be the latest model version 3.6', () => { const mockP1000Specs = { $otSharedSchema: '#/pipette/schemas/2/pipetteGeometrySchema.json', availableSensors: { @@ -77,7 +77,7 @@ describe('pipette data accessors', () => { channels: 1, displayCategory: 'FLEX', displayName: 'Flex 1-Channel 1000 μL', - dropTipConfigurations: { plungerEject: { current: 1, speed: 10 } }, + dropTipConfigurations: { plungerEject: { current: 1, speed: 15 } }, liquids: { default: { $otSharedSchema: @@ -124,7 +124,7 @@ describe('pipette data accessors', () => { plungerHomingConfigurations: { current: 1, speed: 30 }, plungerMotorConfigurations: { idle: 0.3, run: 1 }, plungerPositionsConfigurations: { - default: { blowout: 76.5, bottom: 71.5, drop: 90.5, top: 0.5 }, + default: { blowout: 76.5, bottom: 71.5, drop: 90.5, top: 0 }, }, quirks: [], shaftDiameter: 4.5, @@ -142,7 +142,7 @@ describe('pipette data accessors', () => { ) }) }) - it('returns the correct liquid info for a p50 pipette with default and lowVolume', () => { + it('returns the correct liquid info for a p50 pipette model version with default and lowVolume', () => { const tiprack50uL = 'opentrons/opentrons_flex_96_tiprack_50ul/1' const tiprackFilter50uL = 'opentrons/opentrons_flex_96_filtertiprack_50ul/1' @@ -158,6 +158,7 @@ describe('pipette data accessors', () => { minVolume: 5, supportedTips: { t50: { + uiMaxFlowRate: 47, aspirate: { default: { 1: expect.anything(), @@ -205,27 +206,28 @@ describe('pipette data accessors', () => { minVolume: 1, supportedTips: { t50: { + uiMaxFlowRate: 26.7, aspirate: { default: { 1: expect.anything(), }, }, defaultAspirateFlowRate: { - default: 35, + default: 26.7, valuesByApiLevel: { - 2.14: 35, + 2.14: 26.7, }, }, defaultBlowOutFlowRate: { - default: 57, + default: 26.7, valuesByApiLevel: { - 2.14: 57, + 2.14: 26.7, }, }, defaultDispenseFlowRate: { - default: 57, + default: 26.7, valuesByApiLevel: { - 2.14: 57, + 2.14: 26.7, }, }, defaultFlowAcceleration: 1200, diff --git a/shared-data/js/constants.ts b/shared-data/js/constants.ts index 1b944418e0e..71b4813c07e 100644 --- a/shared-data/js/constants.ts +++ b/shared-data/js/constants.ts @@ -1,5 +1,5 @@ import type { CutoutFixtureId, CutoutId, AddressableAreaName } from '../deck' -import type { ModuleType } from './types' +import type { ModuleModel, ModuleType } from './types' // constants for dealing with robot coordinate system (eg in labwareTools) export const SLOT_LENGTH_MM = 127.76 // along X axis in robot coordinate system @@ -230,6 +230,16 @@ export const STAGING_AREA_CUTOUTS: CutoutId[] = [ 'cutoutD3', ] +export const TEMPERATURE_MODULE_CUTOUTS: CutoutId[] = [ + ...SINGLE_RIGHT_CUTOUTS, + ...SINGLE_LEFT_CUTOUTS, +] +export const HEATER_SHAKER_CUTOUTS: CutoutId[] = [ + ...SINGLE_RIGHT_CUTOUTS, + ...SINGLE_LEFT_CUTOUTS, +] +export const THERMOCYCLER_MODULE_CUTOUTS: CutoutId[] = ['cutoutA1', 'cutoutB1'] + export const WASTE_CHUTE_CUTOUT: 'cutoutD3' = 'cutoutD3' export const A1_ADDRESSABLE_AREA: 'A1' = 'A1' @@ -275,6 +285,114 @@ export const NINETY_SIX_CHANNEL_WASTE_CHUTE_ADDRESSABLE_AREA: '96ChannelWasteChu export const GRIPPER_WASTE_CHUTE_ADDRESSABLE_AREA: 'gripperWasteChute' = 'gripperWasteChute' +export const THERMOCYCLER_ADDRESSABLE_AREA: 'thermocyclerModuleV2' = + 'thermocyclerModuleV2' +export const HEATERSHAKER_A1_ADDRESSABLE_AREA: 'heaterShakerV1A1' = + 'heaterShakerV1A1' +export const HEATERSHAKER_B1_ADDRESSABLE_AREA: 'heaterShakerV1B1' = + 'heaterShakerV1B1' +export const HEATERSHAKER_C1_ADDRESSABLE_AREA: 'heaterShakerV1C1' = + 'heaterShakerV1C1' +export const HEATERSHAKER_D1_ADDRESSABLE_AREA: 'heaterShakerV1D1' = + 'heaterShakerV1D1' +export const HEATERSHAKER_A3_ADDRESSABLE_AREA: 'heaterShakerV1A3' = + 'heaterShakerV1A3' +export const HEATERSHAKER_B3_ADDRESSABLE_AREA: 'heaterShakerV1B3' = + 'heaterShakerV1B3' +export const HEATERSHAKER_C3_ADDRESSABLE_AREA: 'heaterShakerV1C3' = + 'heaterShakerV1C3' +export const HEATERSHAKER_D3_ADDRESSABLE_AREA: 'heaterShakerV1D3' = + 'heaterShakerV1D3' +export const TEMPERATURE_MODULE_A1_ADDRESSABLE_AREA: 'temperatureModuleV2A1' = + 'temperatureModuleV2A1' +export const TEMPERATURE_MODULE_B1_ADDRESSABLE_AREA: 'temperatureModuleV2B1' = + 'temperatureModuleV2B1' +export const TEMPERATURE_MODULE_C1_ADDRESSABLE_AREA: 'temperatureModuleV2C1' = + 'temperatureModuleV2C1' +export const TEMPERATURE_MODULE_D1_ADDRESSABLE_AREA: 'temperatureModuleV2D1' = + 'temperatureModuleV2D1' +export const TEMPERATURE_MODULE_A3_ADDRESSABLE_AREA: 'temperatureModuleV2A3' = + 'temperatureModuleV2A3' +export const TEMPERATURE_MODULE_B3_ADDRESSABLE_AREA: 'temperatureModuleV2B3' = + 'temperatureModuleV2B3' +export const TEMPERATURE_MODULE_C3_ADDRESSABLE_AREA: 'temperatureModuleV2C3' = + 'temperatureModuleV2C3' +export const TEMPERATURE_MODULE_D3_ADDRESSABLE_AREA: 'temperatureModuleV2D3' = + 'temperatureModuleV2D3' + +export const MAGNETIC_BLOCK_A1_ADDRESSABLE_AREA: 'magneticBlockV1A1' = + 'magneticBlockV1A1' +export const MAGNETIC_BLOCK_B1_ADDRESSABLE_AREA: 'magneticBlockV1B1' = + 'magneticBlockV1B1' +export const MAGNETIC_BLOCK_C1_ADDRESSABLE_AREA: 'magneticBlockV1C1' = + 'magneticBlockV1C1' +export const MAGNETIC_BLOCK_D1_ADDRESSABLE_AREA: 'magneticBlockV1D1' = + 'magneticBlockV1D1' +export const MAGNETIC_BLOCK_A2_ADDRESSABLE_AREA: 'magneticBlockV1A2' = + 'magneticBlockV1A2' +export const MAGNETIC_BLOCK_B2_ADDRESSABLE_AREA: 'magneticBlockV1B2' = + 'magneticBlockV1B2' +export const MAGNETIC_BLOCK_C2_ADDRESSABLE_AREA: 'magneticBlockV1C2' = + 'magneticBlockV1C2' +export const MAGNETIC_BLOCK_D2_ADDRESSABLE_AREA: 'magneticBlockV1D2' = + 'magneticBlockV1D2' +export const MAGNETIC_BLOCK_A3_ADDRESSABLE_AREA: 'magneticBlockV1A3' = + 'magneticBlockV1A3' +export const MAGNETIC_BLOCK_B3_ADDRESSABLE_AREA: 'magneticBlockV1B3' = + 'magneticBlockV1B3' +export const MAGNETIC_BLOCK_C3_ADDRESSABLE_AREA: 'magneticBlockV1C3' = + 'magneticBlockV1C3' +export const MAGNETIC_BLOCK_D3_ADDRESSABLE_AREA: 'magneticBlockV1D3' = + 'magneticBlockV1D3' + +export const MAGNETIC_BLOCK_ADDRESSABLE_AREAS: AddressableAreaName[] = [ + MAGNETIC_BLOCK_A1_ADDRESSABLE_AREA, + MAGNETIC_BLOCK_B1_ADDRESSABLE_AREA, + MAGNETIC_BLOCK_C1_ADDRESSABLE_AREA, + MAGNETIC_BLOCK_D1_ADDRESSABLE_AREA, + MAGNETIC_BLOCK_A2_ADDRESSABLE_AREA, + MAGNETIC_BLOCK_B2_ADDRESSABLE_AREA, + MAGNETIC_BLOCK_C2_ADDRESSABLE_AREA, + MAGNETIC_BLOCK_D2_ADDRESSABLE_AREA, + MAGNETIC_BLOCK_A3_ADDRESSABLE_AREA, + MAGNETIC_BLOCK_B3_ADDRESSABLE_AREA, + MAGNETIC_BLOCK_C3_ADDRESSABLE_AREA, + MAGNETIC_BLOCK_D3_ADDRESSABLE_AREA, +] + +export const TEMPERATURE_MODULE_ADDRESSABLE_AREAS: AddressableAreaName[] = [ + TEMPERATURE_MODULE_A1_ADDRESSABLE_AREA, + TEMPERATURE_MODULE_B1_ADDRESSABLE_AREA, + TEMPERATURE_MODULE_C1_ADDRESSABLE_AREA, + TEMPERATURE_MODULE_D1_ADDRESSABLE_AREA, + TEMPERATURE_MODULE_A3_ADDRESSABLE_AREA, + TEMPERATURE_MODULE_B3_ADDRESSABLE_AREA, + TEMPERATURE_MODULE_C3_ADDRESSABLE_AREA, + TEMPERATURE_MODULE_D3_ADDRESSABLE_AREA, +] + +export const HEATERSHAKER_ADDRESSABLE_AREAS: AddressableAreaName[] = [ + HEATERSHAKER_A1_ADDRESSABLE_AREA, + HEATERSHAKER_B1_ADDRESSABLE_AREA, + HEATERSHAKER_C1_ADDRESSABLE_AREA, + HEATERSHAKER_D1_ADDRESSABLE_AREA, + HEATERSHAKER_A3_ADDRESSABLE_AREA, + HEATERSHAKER_B3_ADDRESSABLE_AREA, + HEATERSHAKER_C3_ADDRESSABLE_AREA, + HEATERSHAKER_D3_ADDRESSABLE_AREA, +] + +export const FLEX_USB_MODULE_ADDRESSABLE_AREAS: AddressableAreaName[] = [ + THERMOCYCLER_ADDRESSABLE_AREA, + ...HEATERSHAKER_ADDRESSABLE_AREAS, + ...TEMPERATURE_MODULE_ADDRESSABLE_AREAS, +] + +export const FLEX_MODULE_ADDRESSABLE_AREAS: AddressableAreaName[] = [ + ...FLEX_USB_MODULE_ADDRESSABLE_AREAS, + ...MAGNETIC_BLOCK_ADDRESSABLE_AREAS, +] + export const ADDRESSABLE_AREA_1: '1' = '1' export const ADDRESSABLE_AREA_2: '2' = '2' export const ADDRESSABLE_AREA_3: '3' = '3' @@ -359,6 +477,42 @@ export const STAGING_AREA_SLOT_WITH_WASTE_CHUTE_RIGHT_ADAPTER_COVERED_FIXTURE: ' export const STAGING_AREA_SLOT_WITH_WASTE_CHUTE_RIGHT_ADAPTER_NO_COVER_FIXTURE: 'stagingAreaSlotWithWasteChuteRightAdapterNoCover' = 'stagingAreaSlotWithWasteChuteRightAdapterNoCover' +export const HEATERSHAKER_MODULE_V1_FIXTURE: 'heaterShakerModuleV1' = + 'heaterShakerModuleV1' +export const TEMPERATURE_MODULE_V2_FIXTURE: 'temperatureModuleV2' = + 'temperatureModuleV2' +export const MAGNETIC_BLOCK_V1_FIXTURE: 'magneticBlockV1' = 'magneticBlockV1' +export const STAGING_AREA_SLOT_WITH_MAGNETIC_BLOCK_V1_FIXTURE: 'stagingAreaSlotWithMagneticBlockV1' = + 'stagingAreaSlotWithMagneticBlockV1' +export const THERMOCYCLER_V2_REAR_FIXTURE: 'thermocyclerModuleV2Rear' = + 'thermocyclerModuleV2Rear' +export const THERMOCYCLER_V2_FRONT_FIXTURE: 'thermocyclerModuleV2Front' = + 'thermocyclerModuleV2Front' + +export const MODULE_FIXTURES_BY_MODEL: { + [moduleModel in ModuleModel]?: CutoutFixtureId[] +} = { + [HEATERSHAKER_MODULE_V1]: [HEATERSHAKER_MODULE_V1_FIXTURE], + [TEMPERATURE_MODULE_V2]: [TEMPERATURE_MODULE_V2_FIXTURE], + [MAGNETIC_BLOCK_V1]: [MAGNETIC_BLOCK_V1_FIXTURE], + [THERMOCYCLER_MODULE_V2]: [ + THERMOCYCLER_V2_REAR_FIXTURE, + THERMOCYCLER_V2_FRONT_FIXTURE, + ], +} + +export const FLEX_USB_MODULE_FIXTURES: CutoutFixtureId[] = [ + HEATERSHAKER_MODULE_V1_FIXTURE, + TEMPERATURE_MODULE_V2_FIXTURE, + THERMOCYCLER_V2_REAR_FIXTURE, + THERMOCYCLER_V2_FRONT_FIXTURE, +] + +export const MAGNETIC_BLOCK_FIXTURES: CutoutFixtureId[] = [ + MAGNETIC_BLOCK_V1_FIXTURE, + STAGING_AREA_SLOT_WITH_MAGNETIC_BLOCK_V1_FIXTURE, +] + export const SINGLE_SLOT_FIXTURES: CutoutFixtureId[] = [ SINGLE_LEFT_SLOT_FIXTURE, SINGLE_CENTER_SLOT_FIXTURE, diff --git a/shared-data/js/deck/index.ts b/shared-data/js/deck/index.ts index 786325be5a7..fce6ffb05fe 100644 --- a/shared-data/js/deck/index.ts +++ b/shared-data/js/deck/index.ts @@ -1,5 +1,5 @@ -import flexDeckDefV4 from '../../deck/definitions/4/ot3_standard.json' -import ot2DeckDefV4 from '../../deck/definitions/4/ot2_standard.json' -import ot2DeckDefShortFixedTrashV4 from '../../deck/definitions/4/ot2_short_trash.json' +import flexDeckDefV5 from '../../deck/definitions/5/ot3_standard.json' +import ot2DeckDefV5 from '../../deck/definitions/5/ot2_standard.json' +import ot2DeckDefShortFixedTrashV5 from '../../deck/definitions/5/ot2_short_trash.json' -export { ot2DeckDefV4, ot2DeckDefShortFixedTrashV4, flexDeckDefV4 } +export { ot2DeckDefV5, ot2DeckDefShortFixedTrashV5, flexDeckDefV5 } diff --git a/shared-data/js/fixtures.ts b/shared-data/js/fixtures.ts index 7e2f117bca8..057bce01503 100644 --- a/shared-data/js/fixtures.ts +++ b/shared-data/js/fixtures.ts @@ -6,9 +6,57 @@ import { WASTE_CHUTE_RIGHT_ADAPTER_NO_COVER_FIXTURE, STAGING_AREA_SLOT_WITH_WASTE_CHUTE_RIGHT_ADAPTER_COVERED_FIXTURE, STAGING_AREA_SLOT_WITH_WASTE_CHUTE_RIGHT_ADAPTER_NO_COVER_FIXTURE, + A1_ADDRESSABLE_AREA, + A2_ADDRESSABLE_AREA, + A3_ADDRESSABLE_AREA, + B1_ADDRESSABLE_AREA, + B2_ADDRESSABLE_AREA, + B3_ADDRESSABLE_AREA, + C1_ADDRESSABLE_AREA, + C2_ADDRESSABLE_AREA, + C3_ADDRESSABLE_AREA, + D1_ADDRESSABLE_AREA, + D2_ADDRESSABLE_AREA, + D3_ADDRESSABLE_AREA, + ADDRESSABLE_AREA_1, + ADDRESSABLE_AREA_2, + ADDRESSABLE_AREA_3, + ADDRESSABLE_AREA_4, + ADDRESSABLE_AREA_5, + ADDRESSABLE_AREA_6, + ADDRESSABLE_AREA_7, + ADDRESSABLE_AREA_8, + ADDRESSABLE_AREA_9, + ADDRESSABLE_AREA_10, + ADDRESSABLE_AREA_11, + HEATERSHAKER_MODULE_V1_FIXTURE, + HEATERSHAKER_MODULE_V1, + TEMPERATURE_MODULE_V2_FIXTURE, + TEMPERATURE_MODULE_V2, + MAGNETIC_BLOCK_V1_FIXTURE, + MAGNETIC_BLOCK_V1, + THERMOCYCLER_V2_REAR_FIXTURE, + THERMOCYCLER_MODULE_V2, + THERMOCYCLER_V2_FRONT_FIXTURE, + MODULE_FIXTURES_BY_MODEL, + STAGING_AREA_SLOT_WITH_MAGNETIC_BLOCK_V1_FIXTURE, } from './constants' -import type { CutoutFixtureId, CutoutId, OT2CutoutId } from '../deck' -import type { AddressableArea, CoordinateTuple, DeckDefinition } from './types' +import { getModuleDisplayName } from './modules' +import { getCutoutIdForSlotName } from './helpers' +import type { + AddressableAreaName, + CutoutFixtureId, + CutoutId, + OT2CutoutId, +} from '../deck' +import type { + AddressableArea, + CoordinateTuple, + CutoutFixture, + DeckDefinition, + ModuleModel, +} from './types' +import type { ModuleLocation } from '../command' export function getCutoutDisplayName(cutout: CutoutId): string { return cutout.replace('cutout', '') @@ -107,66 +155,172 @@ export function getAddressableAreaFromSlotId( ) } +export function getCutoutFixtureIdsForModuleModel( + moduleModel: ModuleModel +): CutoutFixtureId[] { + const moduleFixtures = MODULE_FIXTURES_BY_MODEL[moduleModel] + return moduleFixtures ?? [] +} + +export function getCutoutFixturesForModuleModel( + moduleModel: ModuleModel, + deckDef: DeckDefinition +): CutoutFixture[] { + const moduleFixtureIds = getCutoutFixtureIdsForModuleModel(moduleModel) + return moduleFixtureIds.reduce((acc, id) => { + const moduleFixture = deckDef.cutoutFixtures.find(cf => cf.id === id) + return moduleFixture != null ? [...acc, moduleFixture] : acc + }, []) +} + +export function getFixtureIdByCutoutIdFromModuleAnchorCutoutId( + anchorCutoutId: CutoutId | null, + moduleFixtures: CutoutFixture[] // cutout fixtures for a specific module model +): { [cutoutId in CutoutId]?: CutoutFixtureId } { + // find the first fixture for this specific module model that may mount to the cutout implied by the slotName + const anchorFixture = moduleFixtures.find(fixture => + fixture.mayMountTo.some(cutoutId => cutoutId === anchorCutoutId) + ) + if (anchorCutoutId != null && anchorFixture != null) { + const groupedFixtures = anchorFixture.fixtureGroup[anchorCutoutId] + return groupedFixtures?.[0] ?? { [anchorCutoutId]: anchorFixture.id } + } + return {} +} + +export function getFixtureIdByCutoutIdFromModuleSlotName( + slotName: string, + moduleFixtures: CutoutFixture[], // cutout fixtures for a specific module model + deckDef: DeckDefinition +): { [cutoutId in CutoutId]?: CutoutFixtureId } { + const anchorCutoutId = getCutoutIdForSlotName(slotName, deckDef) + return getFixtureIdByCutoutIdFromModuleAnchorCutoutId( + anchorCutoutId, + moduleFixtures + ) +} + +export function getCutoutIdsFromModuleSlotName( + slotName: string, + moduleFixtures: CutoutFixture[], // cutout fixtures for a specific module model + deckDef: DeckDefinition +): CutoutId[] { + const fixtureIdByCutoutId = getFixtureIdByCutoutIdFromModuleSlotName( + slotName, + moduleFixtures, + deckDef + ) + return Object.keys(fixtureIdByCutoutId) as CutoutId[] +} + +export function getAddressableAreaNamesFromLoadedModule( + moduleModel: ModuleModel, + slotName: ModuleLocation['slotName'], + deckDef: DeckDefinition +): AddressableAreaName[] { + const moduleFixtures = getCutoutFixturesForModuleModel(moduleModel, deckDef) + const cutoutIds = getCutoutIdsFromModuleSlotName( + slotName, + moduleFixtures, + deckDef + ) + return moduleFixtures.reduce((acc, cutoutFixture) => { + const providedAddressableAreas = cutoutIds.reduce( + (innerAcc, cutoutId) => { + const newAddressableAreas = + cutoutFixture?.providesAddressableAreas[cutoutId] ?? [] + return [...innerAcc, ...newAddressableAreas] + }, + [] + ) + return [...acc, ...providedAddressableAreas] + }, []) +} + export function getFixtureDisplayName( - cutoutFixtureId: CutoutFixtureId | null + cutoutFixtureId: CutoutFixtureId | null, + usbPortNumber?: number ): string { - if (cutoutFixtureId === STAGING_AREA_RIGHT_SLOT_FIXTURE) { - return 'Staging area slot' - } else if (cutoutFixtureId === TRASH_BIN_ADAPTER_FIXTURE) { - return 'Trash bin' - } else if (cutoutFixtureId === WASTE_CHUTE_RIGHT_ADAPTER_NO_COVER_FIXTURE) { - return 'Waste chute only' - } else if (cutoutFixtureId === WASTE_CHUTE_RIGHT_ADAPTER_COVERED_FIXTURE) { - return 'Waste chute only with cover' - } else if ( - cutoutFixtureId === - STAGING_AREA_SLOT_WITH_WASTE_CHUTE_RIGHT_ADAPTER_NO_COVER_FIXTURE - ) { - return 'Waste chute with staging area slot' - } else if ( - cutoutFixtureId === - STAGING_AREA_SLOT_WITH_WASTE_CHUTE_RIGHT_ADAPTER_COVERED_FIXTURE - ) { - return 'Waste chute with staging area slot and cover' - } else { - return 'Slot' + switch (cutoutFixtureId) { + case STAGING_AREA_RIGHT_SLOT_FIXTURE: + return 'Staging area slot' + case TRASH_BIN_ADAPTER_FIXTURE: + return 'Trash bin' + case WASTE_CHUTE_RIGHT_ADAPTER_NO_COVER_FIXTURE: + return 'Waste chute only' + case WASTE_CHUTE_RIGHT_ADAPTER_COVERED_FIXTURE: + return 'Waste chute only with cover' + case STAGING_AREA_SLOT_WITH_WASTE_CHUTE_RIGHT_ADAPTER_NO_COVER_FIXTURE: + return 'Waste chute with staging area slot' + case STAGING_AREA_SLOT_WITH_WASTE_CHUTE_RIGHT_ADAPTER_COVERED_FIXTURE: + return 'Waste chute with staging area slot and cover' + case HEATERSHAKER_MODULE_V1_FIXTURE: + return usbPortNumber != null + ? `${getModuleDisplayName( + HEATERSHAKER_MODULE_V1 + )} in USB-${usbPortNumber}` + : getModuleDisplayName(HEATERSHAKER_MODULE_V1) + case TEMPERATURE_MODULE_V2_FIXTURE: + return usbPortNumber != null + ? `${getModuleDisplayName( + TEMPERATURE_MODULE_V2 + )} in USB-${usbPortNumber}` + : getModuleDisplayName(TEMPERATURE_MODULE_V2) + case MAGNETIC_BLOCK_V1_FIXTURE: + return `${getModuleDisplayName(MAGNETIC_BLOCK_V1)}` + case STAGING_AREA_SLOT_WITH_MAGNETIC_BLOCK_V1_FIXTURE: + return `${getModuleDisplayName(MAGNETIC_BLOCK_V1)} with staging area slot` + case THERMOCYCLER_V2_REAR_FIXTURE: + return usbPortNumber != null + ? `${getModuleDisplayName( + THERMOCYCLER_MODULE_V2 + )} in USB-${usbPortNumber}` + : getModuleDisplayName(THERMOCYCLER_MODULE_V2) + case THERMOCYCLER_V2_FRONT_FIXTURE: + return usbPortNumber != null + ? `${getModuleDisplayName( + THERMOCYCLER_MODULE_V2 + )} in USB-${usbPortNumber}` + : getModuleDisplayName(THERMOCYCLER_MODULE_V2) + default: + return 'Slot' } } -const STANDARD_OT2_SLOTS = [ - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - '10', - '11', +const STANDARD_OT2_SLOTS: AddressableAreaName[] = [ + ADDRESSABLE_AREA_1, + ADDRESSABLE_AREA_2, + ADDRESSABLE_AREA_3, + ADDRESSABLE_AREA_4, + ADDRESSABLE_AREA_5, + ADDRESSABLE_AREA_6, + ADDRESSABLE_AREA_7, + ADDRESSABLE_AREA_8, + ADDRESSABLE_AREA_9, + ADDRESSABLE_AREA_10, + ADDRESSABLE_AREA_11, ] -const STANDARD_FLEX_SLOTS = [ - 'A1', - 'A2', - 'A3', - 'B1', - 'B2', - 'B3', - 'C1', - 'C2', - 'C3', - 'D1', - 'D2', - 'D3', +const STANDARD_FLEX_SLOTS: AddressableAreaName[] = [ + A1_ADDRESSABLE_AREA, + A2_ADDRESSABLE_AREA, + A3_ADDRESSABLE_AREA, + B1_ADDRESSABLE_AREA, + B2_ADDRESSABLE_AREA, + B3_ADDRESSABLE_AREA, + C1_ADDRESSABLE_AREA, + C2_ADDRESSABLE_AREA, + C3_ADDRESSABLE_AREA, + D1_ADDRESSABLE_AREA, + D2_ADDRESSABLE_AREA, + D3_ADDRESSABLE_AREA, ] export const isAddressableAreaStandardSlot = ( - addressableAreaId: string, + addressableAreaName: AddressableAreaName, deckDef: DeckDefinition ): boolean => (deckDef.robot.model === FLEX_ROBOT_TYPE ? STANDARD_FLEX_SLOTS : STANDARD_OT2_SLOTS - ).includes(addressableAreaId) + ).includes(addressableAreaName) diff --git a/shared-data/js/gripper.ts b/shared-data/js/gripper.ts index 3a2714e30c1..15c1d3f7f7b 100644 --- a/shared-data/js/gripper.ts +++ b/shared-data/js/gripper.ts @@ -18,9 +18,9 @@ export const getGripperDef = ( return gripperV1_2 as GripperDefinition default: console.warn( - `Could not find a gripper with model ${gripperModel}, falling back to most recent definition: ${GRIPPER_V1_1}` + `Could not find a gripper with model ${gripperModel}, falling back to most recent definition: ${GRIPPER_V1_2}` ) - return gripperV1_1 as GripperDefinition + return gripperV1_2 as GripperDefinition } } diff --git a/shared-data/js/helpers/__tests__/formatRunTimeParameterDefaultValue.test.ts b/shared-data/js/helpers/__tests__/formatRunTimeParameterDefaultValue.test.ts new file mode 100644 index 00000000000..d83239e3ec9 --- /dev/null +++ b/shared-data/js/helpers/__tests__/formatRunTimeParameterDefaultValue.test.ts @@ -0,0 +1,145 @@ +import { describe, it, expect, vi } from 'vitest' +import { formatRunTimeParameterDefaultValue } from '../formatRunTimeParameterDefaultValue' + +import type { RunTimeParameter } from '../../types' + +const capitalizeFirstLetter = (str: string): string => { + return str.charAt(0).toUpperCase() + str.slice(1) +} + +const mockTFunction = vi.fn(str => capitalizeFirstLetter(str)) + +describe('formatRunTimeParameterDefaultValue', () => { + it('should return value with suffix when type is int', () => { + const mockData = { + value: 6, + displayName: 'PCR Cycles', + variableName: 'PCR_CYCLES', + description: 'number of PCR cycles on a thermocycler', + type: 'int', + min: 1, + max: 10, + default: 6, + suffix: 'samples', + } as RunTimeParameter + const result = formatRunTimeParameterDefaultValue(mockData, mockTFunction) + expect(result).toEqual('6 samples') + }) + + it('should return value with suffix when type is float', () => { + const mockData = { + value: 6.5, + displayName: 'EtoH Volume', + variableName: 'ETOH_VOLUME', + description: '70% ethanol volume', + type: 'float', + suffix: 'mL', + min: 1.5, + max: 10.0, + default: 6.5, + } as RunTimeParameter + const result = formatRunTimeParameterDefaultValue(mockData, mockTFunction) + expect(result).toEqual('6.5 mL') + }) + + it('should return value when type is str', () => { + const mockData = { + value: 'left', + displayName: 'pipette mount', + variableName: 'mount', + description: 'pipette mount', + type: 'str', + choices: [ + { + displayName: 'Left', + value: 'left', + }, + { + displayName: 'Right', + value: 'right', + }, + ], + default: 'left', + } as RunTimeParameter + const result = formatRunTimeParameterDefaultValue(mockData, mockTFunction) + expect(result).toEqual('Left') + }) + + it('should return value when type is int choice with suffix', () => { + const mockData = { + value: 5, + displayName: 'num', + variableName: 'number', + description: 'its just number', + type: 'int', + suffix: 'mL', + min: 1, + max: 10, + choices: [ + { + displayName: 'one', + value: 1, + }, + { + displayName: 'six', + value: 6, + }, + ], + default: 5, + } as RunTimeParameter + const result = formatRunTimeParameterDefaultValue(mockData, mockTFunction) + expect(result).toEqual('5 mL') + }) + + it('should return value when type is float choice with suffix', () => { + const mockData = { + value: 5.0, + displayName: 'num', + variableName: 'number', + description: 'its just number', + type: 'float', + suffix: 'mL', + min: 1.0, + max: 10.0, + choices: [ + { + displayName: 'one', + value: 1.0, + }, + { + displayName: 'six', + value: 6.0, + }, + ], + default: 5.0, + } as RunTimeParameter + const result = formatRunTimeParameterDefaultValue(mockData, mockTFunction) + expect(result).toEqual('5 mL') + }) + + it('should return value when type is boolean true', () => { + const mockData = { + value: true, + displayName: 'Deactivate Temperatures', + variableName: 'DEACTIVATE_TEMP', + description: 'deactivate temperature on the module', + type: 'bool', + default: true, + } as RunTimeParameter + const result = formatRunTimeParameterDefaultValue(mockData, mockTFunction) + expect(result).toEqual('On') + }) + + it('should return value when type is boolean false', () => { + const mockData = { + value: false, + displayName: 'Dry Run', + variableName: 'DRYRUN', + description: 'Is this a dry or wet run? Wet is true, dry is false', + type: 'bool', + default: false, + } as RunTimeParameter + const result = formatRunTimeParameterDefaultValue(mockData, mockTFunction) + expect(result).toEqual('Off') + }) +}) diff --git a/shared-data/js/helpers/__tests__/formatRunTimeParameterValue.test.ts b/shared-data/js/helpers/__tests__/formatRunTimeParameterValue.test.ts index 2f78d99e11c..8e228cb6dbc 100644 --- a/shared-data/js/helpers/__tests__/formatRunTimeParameterValue.test.ts +++ b/shared-data/js/helpers/__tests__/formatRunTimeParameterValue.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, vi } from 'vitest' -import { formatRunTimeParameterDefaultValue } from '../formatRunTimeParameterDefaultValue' +import { formatRunTimeParameterValue } from '../formatRunTimeParameterValue' import type { RunTimeParameter } from '../../types' @@ -21,7 +21,7 @@ describe('utils-formatRunTimeParameterDefaultValue', () => { max: 10, default: 6, } as RunTimeParameter - const result = formatRunTimeParameterDefaultValue(mockData, mockTFunction) + const result = formatRunTimeParameterValue(mockData, mockTFunction) expect(result).toEqual('6') }) @@ -37,7 +37,7 @@ describe('utils-formatRunTimeParameterDefaultValue', () => { max: 10.0, default: 6.5, } as RunTimeParameter - const result = formatRunTimeParameterDefaultValue(mockData, mockTFunction) + const result = formatRunTimeParameterValue(mockData, mockTFunction) expect(result).toEqual('6.5 mL') }) @@ -60,7 +60,7 @@ describe('utils-formatRunTimeParameterDefaultValue', () => { ], default: 'left', } as RunTimeParameter - const result = formatRunTimeParameterDefaultValue(mockData, mockTFunction) + const result = formatRunTimeParameterValue(mockData, mockTFunction) expect(result).toEqual('Left') }) @@ -86,7 +86,7 @@ describe('utils-formatRunTimeParameterDefaultValue', () => { ], default: 5, } as RunTimeParameter - const result = formatRunTimeParameterDefaultValue(mockData, mockTFunction) + const result = formatRunTimeParameterValue(mockData, mockTFunction) expect(result).toEqual('5 mL') }) @@ -112,7 +112,7 @@ describe('utils-formatRunTimeParameterDefaultValue', () => { ], default: 5.0, } as RunTimeParameter - const result = formatRunTimeParameterDefaultValue(mockData, mockTFunction) + const result = formatRunTimeParameterValue(mockData, mockTFunction) expect(result).toEqual('5 mL') }) @@ -125,7 +125,7 @@ describe('utils-formatRunTimeParameterDefaultValue', () => { type: 'bool', default: true, } as RunTimeParameter - const result = formatRunTimeParameterDefaultValue(mockData, mockTFunction) + const result = formatRunTimeParameterValue(mockData, mockTFunction) expect(result).toEqual('On') }) @@ -138,7 +138,7 @@ describe('utils-formatRunTimeParameterDefaultValue', () => { type: 'bool', default: false, } as RunTimeParameter - const result = formatRunTimeParameterDefaultValue(mockData, mockTFunction) + const result = formatRunTimeParameterValue(mockData, mockTFunction) expect(result).toEqual('Off') }) }) diff --git a/shared-data/js/helpers/__tests__/getDeckDefFromLoadedLabware.test.ts b/shared-data/js/helpers/__tests__/getDeckDefFromLoadedLabware.test.ts index 9c7a1318e06..8e34261756b 100644 --- a/shared-data/js/helpers/__tests__/getDeckDefFromLoadedLabware.test.ts +++ b/shared-data/js/helpers/__tests__/getDeckDefFromLoadedLabware.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect } from 'vitest' -import ot2DeckDef from '../../../deck/definitions/4/ot2_standard.json' -import ot3DeckDef from '../../../deck/definitions/4/ot3_standard.json' +import ot2DeckDef from '../../../deck/definitions/5/ot2_standard.json' +import ot3DeckDef from '../../../deck/definitions/5/ot3_standard.json' import { getDeckDefFromRobotType } from '..' describe('getDeckDefFromRobotType', () => { diff --git a/shared-data/js/helpers/__tests__/getFlexSurroundingSlots.test.ts b/shared-data/js/helpers/__tests__/getFlexSurroundingSlots.test.ts new file mode 100644 index 00000000000..a91d2f737c5 --- /dev/null +++ b/shared-data/js/helpers/__tests__/getFlexSurroundingSlots.test.ts @@ -0,0 +1,30 @@ +import { describe, it, expect } from 'vitest' +import { getFlexSurroundingSlots } from '../getFlexSurroundingSlots' + +describe('getFlexSurroundingSlots', () => { + it('returns slots when slot is D2', () => { + const results = getFlexSurroundingSlots('D2', []) + expect(results).toStrictEqual(['C1', 'C2', 'C3', 'D1', 'D3']) + }) + it('returns slots when selected is a center slot', () => { + const results = getFlexSurroundingSlots('C2', []) + expect(results).toStrictEqual([ + 'B1', + 'B2', + 'B3', + 'C1', + 'C3', + 'D1', + 'D2', + 'D3', + ]) + }) + it('returns slots when selected is a column 3 with staging areas present', () => { + const results = getFlexSurroundingSlots('B3', ['A4']) + expect(results).toStrictEqual(['A2', 'A3', 'A4', 'B2', 'C2', 'C3']) + }) + it('returns slots when selected is a corner, A1', () => { + const results = getFlexSurroundingSlots('A1', ['A4']) + expect(results).toStrictEqual(['A2', 'B1', 'B2']) + }) +}) diff --git a/shared-data/js/helpers/__tests__/orderRuntimeParameterRangeOptions.test.ts b/shared-data/js/helpers/__tests__/orderRuntimeParameterRangeOptions.test.ts index 2a5b62b265d..ca15c35ff42 100644 --- a/shared-data/js/helpers/__tests__/orderRuntimeParameterRangeOptions.test.ts +++ b/shared-data/js/helpers/__tests__/orderRuntimeParameterRangeOptions.test.ts @@ -29,13 +29,13 @@ describe('orderRuntimeParameterRangeOptions', () => { expect(result).toEqual('16, 20') }) - it('should return alphabetical order when choices are number', () => { + it('should return the original order when range is not numerical range', () => { const mockChoices: Choice[] = [ { displayName: 'Single channel 50µL', value: 'flex_1channel_50' }, { displayName: 'Eight Channel 50µL', value: 'flex_8channel_50' }, ] const result = orderRuntimeParameterRangeOptions(mockChoices) - expect(result).toEqual('Eight Channel 50µL, Single channel 50µL') + expect(result).toEqual('Single channel 50µL, Eight Channel 50µL') }) it('should return empty string choices > 3', () => { diff --git a/shared-data/js/helpers/formatRunTimeParameterDefaultValue.ts b/shared-data/js/helpers/formatRunTimeParameterDefaultValue.ts index aa7d16a256f..3ac5cda5bfa 100644 --- a/shared-data/js/helpers/formatRunTimeParameterDefaultValue.ts +++ b/shared-data/js/helpers/formatRunTimeParameterDefaultValue.ts @@ -1,5 +1,15 @@ import type { RunTimeParameter } from '../types' +/** + * Formats the runtime parameter's default value. + * + * @param {RunTimeParameter} runTimeParameter - The runtime parameter whose default value is to be formatted. + * @param {Function} [t] - An optional function for localization. + * + * @returns {string} The formatted default value of the runtime parameter. + * + */ + export const formatRunTimeParameterDefaultValue = ( runTimeParameter: RunTimeParameter, t?: any diff --git a/shared-data/js/helpers/formatRunTimeParameterMinMax.ts b/shared-data/js/helpers/formatRunTimeParameterMinMax.ts index 36444f89601..632dec5c020 100644 --- a/shared-data/js/helpers/formatRunTimeParameterMinMax.ts +++ b/shared-data/js/helpers/formatRunTimeParameterMinMax.ts @@ -1,4 +1,25 @@ import type { RunTimeParameter } from '../types' +/** + * Formats the runtime parameter's minimum and maximum values. + * + * @param {RunTimeParameter} runTimeParameter - The runtime parameter whose min and max values are to be formatted. + * + * @returns {string} The formatted min-max value of the runtime parameter. + * + * @example + * const runTimeParameter = { + * value: 6.5, + * displayName: 'EtoH Volume', + * variableName: 'ETOH_VOLUME', + * description: '70% ethanol volume', + * type: 'float', + * suffix: 'mL', + * min: 1.5, + * max: 10.0, + * default: 6.5, + * } + * console.log(formatRunTimeParameterMinMax(runTimeParameter)); // "1.5-10.0" + */ export const formatRunTimeParameterMinMax = ( runTimeParameter: RunTimeParameter diff --git a/shared-data/js/helpers/formatRunTimeParameterValue.ts b/shared-data/js/helpers/formatRunTimeParameterValue.ts index a75bee5fd68..a6a3ad4d7ec 100644 --- a/shared-data/js/helpers/formatRunTimeParameterValue.ts +++ b/shared-data/js/helpers/formatRunTimeParameterValue.ts @@ -1,5 +1,15 @@ import type { RunTimeParameter } from '../types' +/** + * Formats the runtime parameter value. + * + * @param {RunTimeParameter} runTimeParameter - The runtime parameter to be formatted. + * @param {Function} t - A function for localization. + * + * @returns {string} The formatted runtime parameter value. + * + */ + export const formatRunTimeParameterValue = ( runTimeParameter: RunTimeParameter, t: any diff --git a/shared-data/js/helpers/getAddressableAreasInProtocol.ts b/shared-data/js/helpers/getAddressableAreasInProtocol.ts index 1ca3013930a..81222777db2 100644 --- a/shared-data/js/helpers/getAddressableAreasInProtocol.ts +++ b/shared-data/js/helpers/getAddressableAreasInProtocol.ts @@ -1,5 +1,8 @@ import { MOVABLE_TRASH_A3_ADDRESSABLE_AREA } from '../constants' -import { getAddressableAreaFromSlotId } from '../fixtures' +import { + getAddressableAreaNamesFromLoadedModule, + getAddressableAreaFromSlotId, +} from '../fixtures' import type { AddressableAreaName } from '../../deck' import type { ProtocolAnalysisOutput } from '../../protocol' import type { CompletedProtocolAnalysis, DeckDefinition } from '../types' @@ -12,16 +15,15 @@ export function getAddressableAreasInProtocol( const addressableAreasFromCommands = commands.reduce( (acc, command) => { + const { commandType, params } = command if ( - command.commandType === 'moveLabware' && - command.params.newLocation !== 'offDeck' && - 'slotName' in command.params.newLocation && - !acc.includes( - command.params.newLocation.slotName as AddressableAreaName - ) + commandType === 'moveLabware' && + params.newLocation !== 'offDeck' && + 'slotName' in params.newLocation && + !acc.includes(params.newLocation.slotName as AddressableAreaName) ) { const addressableAreaName = getAddressableAreaFromSlotId( - command.params.newLocation.slotName, + params.newLocation.slotName, deckDef )?.id @@ -31,51 +33,61 @@ export function getAddressableAreasInProtocol( return [...acc, addressableAreaName] } } else if ( - command.commandType === 'moveLabware' && - command.params.newLocation !== 'offDeck' && - 'addressableAreaName' in command.params.newLocation && - !acc.includes(command.params.newLocation.addressableAreaName) + commandType === 'moveLabware' && + params.newLocation !== 'offDeck' && + 'addressableAreaName' in params.newLocation && + !acc.includes(params.newLocation.addressableAreaName) ) { - return [...acc, command.params.newLocation.addressableAreaName] + return [...acc, params.newLocation.addressableAreaName] } else if ( - (command.commandType === 'loadLabware' || - command.commandType === 'loadModule') && - command.params.location !== 'offDeck' && - 'slotName' in command.params.location && - !acc.includes(command.params.location.slotName as AddressableAreaName) + commandType === 'loadLabware' && + params.location !== 'offDeck' && + 'slotName' in params.location && + !acc.includes(params.location.slotName as AddressableAreaName) ) { const addressableAreaName = getAddressableAreaFromSlotId( - command.params.location.slotName, + params.location.slotName, deckDef )?.id // do not add addressable area name for legacy trash labware if ( addressableAreaName == null || - ('loadName' in command.params && - command.params.loadName === 'opentrons_1_trash_3200ml_fixed') + ('loadName' in params && + params.loadName === 'opentrons_1_trash_3200ml_fixed') ) { return acc } else { return [...acc, addressableAreaName] } } else if ( - command.commandType === 'loadLabware' && - command.params.location !== 'offDeck' && - 'addressableAreaName' in command.params.location && - !acc.includes(command.params.location.addressableAreaName) + commandType === 'loadModule' && + !acc.includes(params.location.slotName as AddressableAreaName) + ) { + const addressableAreaNames = getAddressableAreaNamesFromLoadedModule( + params.model, + params.location.slotName, + deckDef + ) + + return [...acc, ...addressableAreaNames] + } else if ( + commandType === 'loadLabware' && + params.location !== 'offDeck' && + 'addressableAreaName' in params.location && + !acc.includes(params.location.addressableAreaName) ) { - return [...acc, command.params.location.addressableAreaName] + return [...acc, params.location.addressableAreaName] } else if ( - command.commandType === 'moveToAddressableArea' && - !acc.includes(command.params.addressableAreaName) + commandType === 'moveToAddressableArea' && + !acc.includes(params.addressableAreaName) ) { - return [...acc, command.params.addressableAreaName] + return [...acc, params.addressableAreaName] } else if ( - command.commandType === 'moveToAddressableAreaForDropTip' && - !acc.includes(command.params.addressableAreaName) + commandType === 'moveToAddressableAreaForDropTip' && + !acc.includes(params.addressableAreaName) ) { - return [...acc, command.params.addressableAreaName] + return [...acc, params.addressableAreaName] } else { return acc } diff --git a/shared-data/js/helpers/getFlexSurroundingSlots.ts b/shared-data/js/helpers/getFlexSurroundingSlots.ts new file mode 100644 index 00000000000..9900cee9880 --- /dev/null +++ b/shared-data/js/helpers/getFlexSurroundingSlots.ts @@ -0,0 +1,63 @@ +import type { DeckSlotId } from '../types' + +const FLEX_GRID = [ + ['A1', 'A2', 'A3'], + ['B1', 'B2', 'B3'], + ['C1', 'C2', 'C3'], + ['D1', 'D2', 'D3'], +] + +const LETTER_TO_ROW_MAP: Record = { + A: 0, + B: 1, + C: 2, + D: 3, +} + +let COLS = 3 // Initial number of columns in each row +const ROWS = 4 + +const DIRECTIONS = [ + [-1, -1], // NW + [-1, 0], // N + [-1, 1], // NE + [0, -1], // W + [0, 1], // E + [1, -1], // SW + [1, 0], // S + [1, 1], // SE +] + +export const getFlexSurroundingSlots = ( + slot: DeckSlotId, + stagingAreaSlots: DeckSlotId[] +): DeckSlotId[] => { + // Handle staging area slots + if (stagingAreaSlots.length > 0) { + stagingAreaSlots.forEach((stagingSlot, index) => { + if (stagingSlot) { + FLEX_GRID[index].push(stagingSlot) + } + }) + COLS = Math.max(COLS, FLEX_GRID[0].length) // Update COLS to the maximum row length + } + + const letter = slot.charAt(0) + const col = parseInt(slot.charAt(1)) - 1 // Convert the column to a 0-based index + const row = LETTER_TO_ROW_MAP[letter] + + const surroundingSlots: DeckSlotId[] = [] + + // Iterate through both directions + DIRECTIONS.forEach(([dRow, dCol]) => { + const newRow = row + dRow + const newCol = col + dCol + + if (newRow >= 0 && newRow < ROWS && newCol >= 0 && newCol < COLS) { + surroundingSlots.push(FLEX_GRID[newRow][newCol]) + } + }) + + // Filter out any undefined values from the staging area slots that are not added + return surroundingSlots.filter(slot => slot !== undefined) +} diff --git a/shared-data/js/helpers/getSimplestFlexDeckConfig.ts b/shared-data/js/helpers/getSimplestFlexDeckConfig.ts index e4017199156..65c4ccac3e5 100644 --- a/shared-data/js/helpers/getSimplestFlexDeckConfig.ts +++ b/shared-data/js/helpers/getSimplestFlexDeckConfig.ts @@ -2,7 +2,7 @@ import { FLEX_ROBOT_TYPE } from '../constants' import { getAddressableAreaFromSlotId } from '../fixtures' import { getAddressableAreasInProtocol, getDeckDefFromRobotType } from '.' -import type { AddressableAreaName, CutoutId } from '../../deck' +import type { AddressableAreaName, CutoutFixtureId, CutoutId } from '../../deck' import type { ProtocolAnalysisOutput } from '../../protocol' import type { CutoutConfig, @@ -10,6 +10,7 @@ import type { DeckDefinition, DeckConfiguration, CompletedProtocolAnalysis, + CutoutFixtureGroup, } from '../types' export interface CutoutConfigProtocolSpec extends CutoutConfig { @@ -111,7 +112,6 @@ export function getSimplestDeckConfigForProtocol( } return acc }, FLEX_SIMPLEST_DECK_CONFIG_PROTOCOL_SPEC) - return simplestDeckConfig } @@ -151,6 +151,15 @@ export function getCutoutIdForSlotName( return cutoutIdForSlotName } +export function getFixtureGroupForCutoutFixture( + cutoutFixtureId: CutoutFixtureId, + cutoutFixtures: CutoutFixture[] +): CutoutFixtureGroup { + return ( + cutoutFixtures.find(cf => cf.id === cutoutFixtureId)?.fixtureGroup ?? {} + ) +} + export function getCutoutIdForAddressableArea( addressableArea: AddressableAreaName, cutoutFixtures: CutoutFixture[] diff --git a/shared-data/js/helpers/index.ts b/shared-data/js/helpers/index.ts index 0cb4ec7d88a..791fa1f5db1 100644 --- a/shared-data/js/helpers/index.ts +++ b/shared-data/js/helpers/index.ts @@ -1,8 +1,8 @@ import uniq from 'lodash/uniq' import { OPENTRONS_LABWARE_NAMESPACE } from '../constants' -import standardOt2DeckDef from '../../deck/definitions/4/ot2_standard.json' -import standardFlexDeckDef from '../../deck/definitions/4/ot3_standard.json' +import standardOt2DeckDef from '../../deck/definitions/5/ot2_standard.json' +import standardFlexDeckDef from '../../deck/definitions/5/ot3_standard.json' import type { DeckDefinition, LabwareDefinition2, @@ -27,6 +27,7 @@ export * from './getLoadedLabwareDefinitionsByUri' export * from './getOccludedSlotCountForModule' export * from './labwareInference' export * from './getAddressableAreasInProtocol' +export * from './getFlexSurroundingSlots' export * from './getSimplestFlexDeckConfig' export * from './formatRunTimeParameterDefaultValue' export * from './formatRunTimeParameterValue' diff --git a/shared-data/js/helpers/orderRuntimeParameterRangeOptions.ts b/shared-data/js/helpers/orderRuntimeParameterRangeOptions.ts index c372e992a2b..289dd919b14 100644 --- a/shared-data/js/helpers/orderRuntimeParameterRangeOptions.ts +++ b/shared-data/js/helpers/orderRuntimeParameterRangeOptions.ts @@ -9,19 +9,14 @@ export const isNumeric = (str: string): boolean => { * @param {Choice[]} - The array of Choice * Choice is an object like {displayName: 'Single channel 50µL', value: 'flex_1channel_50' } * @returns {string} The ordered string with "," - * - * examples - * [ - { displayName: '20', value: 20 }, - { displayName: '16', value: 16 }, - ] - return 16, 20 - - [ - { displayName: 'Single channel 50µL', value: 'flex_1channel_50' }, - { displayName: 'Eight Channel 50µL', value: 'flex_8channel_50' }, - ] - return Eight Channel 50µL, Single channel 50µL + * + * @example + * const numChoices = [ + * { displayName: '20', value: 20 }, + * { displayName: '16', value: 16 }, + * ] + * console.log(orderRuntimeParameterRangeOptions(numChoices) // 16,20 + * */ export const orderRuntimeParameterRangeOptions = ( choices: Choice[] @@ -41,6 +36,6 @@ export const orderRuntimeParameterRangeOptions = ( }) .join(', ') } else { - return displayNames.sort().join(', ') + return displayNames.join(', ') } } diff --git a/shared-data/js/pipettes.ts b/shared-data/js/pipettes.ts index d918a2e6bc8..0901d10ae42 100644 --- a/shared-data/js/pipettes.ts +++ b/shared-data/js/pipettes.ts @@ -60,7 +60,7 @@ export function getPipetteNameSpecs( // NOTE: this should NEVER be used in PD, which is model-agnostic export function getPipetteModelSpecs( model: PipetteModel -): PipetteModelSpecs | null | undefined { +): PipetteModelSpecs | null { const modelSpecificFields = pipetteModelSpecs.config[model] const modelFields = modelSpecificFields && @@ -139,24 +139,51 @@ const getChannelsFromString = ( } } } -const getVersionFromGen = (gen: Gen): string | null => { +const getVersionFromGen = (gen: Gen): number => { switch (gen) { case 'gen1': { - return '1_0' + return 1 } case 'gen2': { - return '2_0' + return 2 } case 'gen3': case 'flex': { - return '3_0' + return 3 } default: { - return null + return 0 } } } - +const getHighestVersion = ( + wholeVersion: string, + path: string, + pipetteModel: string, + channels: Channels | null, + majorVersion: number, + highestVersion: string +): string => { + const versionComponents = wholeVersion.split('_') + const majorPathVersion = parseInt(versionComponents[0]) + const minorPathVersion = parseInt(versionComponents[1]) + const highestVersionComponents = highestVersion.split('_') + const minorHighestVersion = parseInt(highestVersionComponents[1]) + if (majorPathVersion === majorVersion) { + // Compare the version number with the current highest version + // and make sure the given model, channels, and major/minor versions + // are found in the path + if ( + minorPathVersion > minorHighestVersion && + path.includes(`${majorPathVersion}_${minorPathVersion}`) && + path.includes(pipetteModel) && + path.includes(channels ?? '') + ) { + highestVersion = `${majorPathVersion}_${minorPathVersion}` + } + } + return highestVersion +} const V2_DEFINITION_TYPES = ['general', 'geometry'] /* takes in pipetteName such as 'p300_single' or 'p300_single_gen1' @@ -173,14 +200,19 @@ export const getPipetteSpecsV2 = ( const nameSplit = name.split('_') const pipetteModel = nameSplit[0] // ex: p300 const channels = getChannelsFromString(nameSplit[1] as PipChannelString) // ex: single -> single_channel - const gen = getVersionFromGen(nameSplit[2] as Gen) - - let version: string + const pipetteGen = getVersionFromGen(nameSplit[2] as Gen) + let version: string = '' + let majorVersion: number // the first 2 conditions are to accommodate version from the pipetteName if (nameSplit.length === 2) { - version = '1_0' - } else if (gen != null) { - version = gen // ex: gen1 -> 1_0 + // special-casing 96-channel + if (channels === 'ninety_six_channel') { + majorVersion = 3 + } else { + majorVersion = 1 + } + } else if (pipetteGen !== 0) { + majorVersion = pipetteGen // ex: gen1 -> 1 // the 'else' is to accommodate the exact version if PipetteModel was added } else { const versionNumber = nameSplit[2].split('v')[1] @@ -190,13 +222,23 @@ export const getPipetteSpecsV2 = ( version = `${versionNumber}_0` // ex: 1 -> 1_0 } } - + let highestVersion: string = '0_0' const generalGeometricMatchingJsons = Object.entries(generalGeometric).reduce( (genericGeometricModules: GeneralGeometricModules[], [path, module]) => { + const wholeVersion = path.split('/')[7] + highestVersion = getHighestVersion( + wholeVersion, + path, + pipetteModel, + channels, + majorVersion, + highestVersion + ) V2_DEFINITION_TYPES.forEach(type => { if ( - `../pipette/definitions/2/${type}/${channels}/${pipetteModel}/${version}.json` === - path + `../pipette/definitions/2/${type}/${channels}/${pipetteModel}/${ + version === '' ? highestVersion : version + }.json` === path ) { genericGeometricModules.push(module.default) } @@ -219,8 +261,9 @@ export const getPipetteSpecsV2 = ( liquidTypes.push(type) } if ( - `../pipette/definitions/2/liquid/${channels}/${pipetteModel}/${type}/${version}.json` === - path + `../pipette/definitions/2/liquid/${channels}/${pipetteModel}/${type}/${ + version === '' ? highestVersion : version + }.json` === path ) { const index = liquidTypes.indexOf(type) const newKeyName = index !== -1 ? liquidTypes[index] : path diff --git a/shared-data/js/types.ts b/shared-data/js/types.ts index 75466e7558e..4d51f992f22 100644 --- a/shared-data/js/types.ts +++ b/shared-data/js/types.ts @@ -270,11 +270,17 @@ export interface DeckCalibrationPoint { displayName: string } +export type CutoutFixtureGroup = { + [cutoutId in CutoutId]?: Array<{ [cutoutId in CutoutId]?: CutoutFixtureId }> +} + export interface CutoutFixture { id: CutoutFixtureId mayMountTo: CutoutId[] displayName: string providesAddressableAreas: Record + expectOpentronsModuleSerialNumber: boolean + fixtureGroup: CutoutFixtureGroup height: number } @@ -486,6 +492,7 @@ export interface SupportedTip { } defaultReturnTipHeight?: number defaultFlowAcceleration?: number + uiMaxFlowRate?: number } export interface SupportedTips { @@ -590,7 +597,7 @@ export interface AnalysisError { createdAt: string } -export interface NumberParameter { +export interface NumberParameter extends BaseRunTimeParameter { type: NumberParameterType min: number max: number @@ -602,13 +609,13 @@ export interface Choice { value: number | boolean | string } -interface ChoiceParameter { +interface ChoiceParameter extends BaseRunTimeParameter { type: RunTimeParameterType choices: Choice[] default: number | boolean | string } -interface BooleanParameter { +interface BooleanParameter extends BaseRunTimeParameter { type: BooleanParameterType default: boolean } @@ -621,7 +628,6 @@ type RunTimeParameterType = | BooleanParameterType | StringParameterType -type ParameterType = NumberParameter | ChoiceParameter | BooleanParameter interface BaseRunTimeParameter { displayName: string variableName: string @@ -630,7 +636,10 @@ interface BaseRunTimeParameter { suffix?: string } -export type RunTimeParameter = BaseRunTimeParameter & ParameterType +export type RunTimeParameter = + | BooleanParameter + | ChoiceParameter + | NumberParameter // TODO(BC, 10/25/2023): this type (and others in this file) probably belong in api-client, not here export interface CompletedProtocolAnalysis { @@ -720,7 +729,8 @@ export type StatusBarAnimations = StatusBarAnimation[] export interface CutoutConfig { cutoutId: CutoutId - cutoutFixtureId: CutoutFixtureId | null + cutoutFixtureId: CutoutFixtureId + opentronsModuleSerialNumber?: string } export type DeckConfiguration = CutoutConfig[] diff --git a/shared-data/pipette/definitions/1/pipetteModelSpecs.json b/shared-data/pipette/definitions/1/pipetteModelSpecs.json index 7a039c0e33f..a66312eb522 100644 --- a/shared-data/pipette/definitions/1/pipetteModelSpecs.json +++ b/shared-data/pipette/definitions/1/pipetteModelSpecs.json @@ -7475,6 +7475,175 @@ "returnTipHeight": 0.78, "idleCurrent": 0.3 }, + "p50_single_v3.6": { + "name": "p50_single_flex", + "backCompatNames": [], + "top": { + "value": 0.5, + "min": 0, + "max": 45, + "units": "mm", + "type": "float" + }, + "bottom": { + "value": 71.5, + "min": 55, + "max": 80, + "type": "float", + "units": "mm" + }, + "blowout": { + "value": 76.5, + "min": 60, + "max": 85, + "units": "mm", + "type": "float" + }, + "dropTip": { + "value": 90.5, + "min": 78, + "max": 119, + "units": "mm", + "type": "float" + }, + "pickUpCurrent": { + "value": 0.15, + "min": 0.05, + "max": 2.0, + "units": "amps", + "type": "float" + }, + "pickUpDistance": { + "value": 15, + "min": 1, + "max": 30, + "units": "mm", + "type": "float" + }, + "pickUpIncrement": { + "value": 0.0, + "min": 0.0, + "max": 10.0, + "units": "mm", + "type": "float" + }, + "pickUpPresses": { + "value": 1, + "min": 0, + "max": 10, + "units": "presses", + "type": "int" + }, + "pickUpSpeed": { + "value": 5, + "min": 1, + "max": 30, + "units": "mm/s", + "type": "float" + }, + "nozzleOffset": [-8.0, -22.0, -259.15], + "modelOffset": [0.0, 0.0, 25.14], + "ulPerMm": [ + { + "aspirate": [ + [0.6464, 0.4817, 0.0427], + [1.0889, 0.2539, 0.1591], + [1.5136, 0.1624, 0.2587], + [1.9108, 0.1042, 0.3467], + [2.2941, 0.0719, 0.4085], + [2.9978, 0.037, 0.4886], + [3.7731, 0.0378, 0.4863], + [4.7575, 0.0516, 0.4342], + [5.5024, 0.011, 0.6275], + [6.2686, 0.0114, 0.6253], + [7.005, 0.0054, 0.6625], + [8.5207, 0.0063, 0.6563], + [10.0034, 0.003, 0.6844], + [11.5075, 0.0031, 0.6833], + [13.0327, 0.0032, 0.6829], + [14.5356, 0.0018, 0.7003], + [17.5447, 0.0014, 0.7063], + [20.5576, 0.0011, 0.7126], + [23.5624, 0.0007, 0.7197], + [26.5785, 0.0007, 0.721], + [29.593, 0.0005, 0.7248], + [32.6109, 0.0004, 0.7268], + [35.6384, 0.0004, 0.727], + [38.6439, 0.0002, 0.7343], + [41.6815, 0.0004, 0.7284], + [44.6895, 0.0002, 0.7372], + [47.6926, 0.0001, 0.7393], + [51.4567, 0.0001, 0.7382] + ], + + "dispense": [ + [0.6464, 0.4817, 0.0427], + [1.0889, 0.2539, 0.1591], + [1.5136, 0.1624, 0.2587], + [1.9108, 0.1042, 0.3467], + [2.2941, 0.0719, 0.4085], + [2.9978, 0.037, 0.4886], + [3.7731, 0.0378, 0.4863], + [4.7575, 0.0516, 0.4342], + [5.5024, 0.011, 0.6275], + [6.2686, 0.0114, 0.6253], + [7.005, 0.0054, 0.6625], + [8.5207, 0.0063, 0.6563], + [10.0034, 0.003, 0.6844], + [11.5075, 0.0031, 0.6833], + [13.0327, 0.0032, 0.6829], + [14.5356, 0.0018, 0.7003], + [17.5447, 0.0014, 0.7063], + [20.5576, 0.0011, 0.7126], + [23.5624, 0.0007, 0.7197], + [26.5785, 0.0007, 0.721], + [29.593, 0.0005, 0.7248], + [32.6109, 0.0004, 0.7268], + [35.6384, 0.0004, 0.727], + [38.6439, 0.0002, 0.7343], + [41.6815, 0.0004, 0.7284], + [44.6895, 0.0002, 0.7372], + [47.6926, 0.0001, 0.7393], + [51.4567, 0.0001, 0.7382] + ] + } + ], + "plungerCurrent": { + "value": 1.0, + "min": 0.1, + "max": 1.5, + "units": "amps", + "type": "float" + }, + "dropTipCurrent": { + "value": 1.0, + "min": 0.1, + "max": 1.25, + "units": "amps", + "type": "float" + }, + "dropTipSpeed": { + "value": 7, + "min": 0.001, + "max": 30, + "units": "mm/sec", + "type": "float" + }, + "tipOverlap": { + "default": 10.5, + "opentrons/opentrons_96_tiprack_50ul/1": 10.5 + }, + "tipLength": { + "value": 78.3, + "units": "mm", + "type": "float", + "min": 0, + "max": 100 + }, + "quirks": [], + "returnTipHeight": 0.78, + "idleCurrent": 0.3 + }, "p50_single_v4.3": { "name": "p50_single_flex", "backCompatNames": [], @@ -10304,6 +10473,175 @@ "quirks": [], "returnTipHeight": 0.83, "idleCurrent": 0.3 + }, + "p1000_96_v3.6": { + "name": "p1000_96", + "backCompatNames": [], + "top": { + "value": 0.5, + "min": 0, + "max": 45, + "units": "mm", + "type": "float" + }, + "bottom": { + "value": 71.5, + "min": 55, + "max": 80, + "type": "float", + "units": "mm" + }, + "blowout": { + "value": 76.5, + "min": 60, + "max": 85, + "units": "mm", + "type": "float" + }, + "dropTip": { + "value": 92.5, + "min": 78, + "max": 119, + "units": "mm", + "type": "float" + }, + "pickUpCurrent": { + "value": 0.5, + "min": 0.05, + "max": 2.0, + "units": "amps", + "type": "float" + }, + "pickUpDistance": { + "value": 13, + "min": 1, + "max": 30, + "units": "mm", + "type": "float" + }, + "pickUpIncrement": { + "value": 0.0, + "min": 0.0, + "max": 10.0, + "units": "mm", + "type": "float" + }, + "pickUpPresses": { + "value": 1, + "min": 0, + "max": 10, + "units": "presses", + "type": "int" + }, + "pickUpSpeed": { + "value": 10, + "min": 1, + "max": 30, + "units": "mm/s", + "type": "float" + }, + "nozzleOffset": [-8.0, -16.0, -259.15], + "modelOffset": [0.0, 0.0, 25.14], + "ulPerMm": [ + { + "aspirate": [ + [0.6464, 0.4817, 0.0427], + [1.0889, 0.2539, 0.1591], + [1.5136, 0.1624, 0.2587], + [1.9108, 0.1042, 0.3467], + [2.2941, 0.0719, 0.4085], + [2.9978, 0.037, 0.4886], + [3.7731, 0.0378, 0.4863], + [4.7575, 0.0516, 0.4342], + [5.5024, 0.011, 0.6275], + [6.2686, 0.0114, 0.6253], + [7.005, 0.0054, 0.6625], + [8.5207, 0.0063, 0.6563], + [10.0034, 0.003, 0.6844], + [11.5075, 0.0031, 0.6833], + [13.0327, 0.0032, 0.6829], + [14.5356, 0.0018, 0.7003], + [17.5447, 0.0014, 0.7063], + [20.5576, 0.0011, 0.7126], + [23.5624, 0.0007, 0.7197], + [26.5785, 0.0007, 0.721], + [29.593, 0.0005, 0.7248], + [32.6109, 0.0004, 0.7268], + [35.6384, 0.0004, 0.727], + [38.6439, 0.0002, 0.7343], + [41.6815, 0.0004, 0.7284], + [44.6895, 0.0002, 0.7372], + [47.6926, 0.0001, 0.7393], + [51.4567, 0.0001, 0.7382] + ], + + "dispense": [ + [0.6464, 0.4817, 0.0427], + [1.0889, 0.2539, 0.1591], + [1.5136, 0.1624, 0.2587], + [1.9108, 0.1042, 0.3467], + [2.2941, 0.0719, 0.4085], + [2.9978, 0.037, 0.4886], + [3.7731, 0.0378, 0.4863], + [4.7575, 0.0516, 0.4342], + [5.5024, 0.011, 0.6275], + [6.2686, 0.0114, 0.6253], + [7.005, 0.0054, 0.6625], + [8.5207, 0.0063, 0.6563], + [10.0034, 0.003, 0.6844], + [11.5075, 0.0031, 0.6833], + [13.0327, 0.0032, 0.6829], + [14.5356, 0.0018, 0.7003], + [17.5447, 0.0014, 0.7063], + [20.5576, 0.0011, 0.7126], + [23.5624, 0.0007, 0.7197], + [26.5785, 0.0007, 0.721], + [29.593, 0.0005, 0.7248], + [32.6109, 0.0004, 0.7268], + [35.6384, 0.0004, 0.727], + [38.6439, 0.0002, 0.7343], + [41.6815, 0.0004, 0.7284], + [44.6895, 0.0002, 0.7372], + [47.6926, 0.0001, 0.7393], + [51.4567, 0.0001, 0.7382] + ] + } + ], + "plungerCurrent": { + "value": 1, + "min": 0.1, + "max": 1.5, + "units": "amps", + "type": "float" + }, + "dropTipCurrent": { + "value": 1, + "min": 0.1, + "max": 1.25, + "units": "amps", + "type": "float" + }, + "dropTipSpeed": { + "value": 10, + "min": 0.001, + "max": 30, + "units": "mm/sec", + "type": "float" + }, + "tipOverlap": { + "default": 10.5, + "opentrons/opentrons_96_tiprack_50ul/1": 10.5 + }, + "tipLength": { + "value": 78.3, + "units": "mm", + "type": "float", + "min": 0, + "max": 100 + }, + "quirks": [], + "returnTipHeight": 0.83, + "idleCurrent": 0.3 } }, "mutableConfigs": [ diff --git a/shared-data/pipette/definitions/2/general/ninety_six_channel/p1000/3_6.json b/shared-data/pipette/definitions/2/general/ninety_six_channel/p1000/3_6.json new file mode 100644 index 00000000000..c59dfce42ab --- /dev/null +++ b/shared-data/pipette/definitions/2/general/ninety_six_channel/p1000/3_6.json @@ -0,0 +1,114 @@ +{ + "$otSharedSchema": "#/pipette/schemas/2/pipettePropertiesSchema.json", + "displayName": "Flex 96-Channel 1000 μL", + "model": "p1000", + "displayCategory": "FLEX", + "pickUpTipConfigurations": { + "pressFit": { + "presses": 1, + "increment": 0.0, + "speedByTipCount": { + "1": 10.0, + "2": 10.0, + "3": 10.0, + "4": 10.0, + "5": 10.0, + "6": 10.0, + "7": 10.0, + "8": 10.0, + "12": 10.0, + "16": 10.0, + "24": 10.0, + "48": 10.0 + }, + "distanceByTipCount": { + "1": 13.0, + "2": 13.0, + "3": 13.0, + "4": 13.0, + "5": 13.0, + "6": 13.0, + "7": 13.0, + "8": 13.0, + "12": 13.0, + "16": 13.0, + "24": 13.0, + "48": 13.0 + }, + + "currentByTipCount": { + "1": 0.2, + "2": 0.25, + "3": 0.3, + "4": 0.35, + "5": 0.4, + "6": 0.45, + "7": 0.5, + "8": 0.55, + "12": 0.19, + "16": 0.25, + "24": 0.38, + "48": 0.75 + } + }, + "camAction": { + "speed": 5.5, + "distance": 10.0, + "prep_move_distance": 8.25, + "prep_move_speed": 10.0, + "connectTiprackDistanceMM": 7.0, + "currentByTipCount": { + "96": 1.5 + } + } + }, + "dropTipConfigurations": { + "camAction": { + "current": 1.5, + "speed": 5.5, + "distance": 10.8, + "prep_move_distance": 19.0, + "prep_move_speed": 10.0 + } + }, + "plungerMotorConfigurations": { + "idle": 0.3, + "run": 0.8 + }, + "plungerPositionsConfigurations": { + "default": { + "top": 0.5, + "bottom": 68.5, + "blowout": 73.5, + "drop": 80 + } + }, + "availableSensors": { + "sensors": ["pressure", "capacitive", "environment"], + "pressure": { + "count": 2 + }, + "capacitive": { + "count": 2 + }, + "environment": { + "count": 1 + } + }, + "partialTipConfigurations": { + "partialTipSupported": true, + "availableConfigurations": [1, 8, 12, 16, 24, 48, 96] + }, + "backCompatNames": [], + "channels": 96, + "shaftDiameter": 4.5, + "shaftULperMM": 15.904, + "backlashDistance": 3.0, + "quirks": [], + "plungerHomingConfigurations": { + "current": 0.8, + "speed": 5 + }, + "tipPresenceCheckDistanceMM": 8.0, + "endTipActionRetractDistanceMM": 2.0 +} diff --git a/shared-data/pipette/definitions/2/general/single_channel/p50/3_6.json b/shared-data/pipette/definitions/2/general/single_channel/p50/3_6.json new file mode 100644 index 00000000000..1f29cbf71f1 --- /dev/null +++ b/shared-data/pipette/definitions/2/general/single_channel/p50/3_6.json @@ -0,0 +1,71 @@ +{ + "$otSharedSchema": "#/pipette/schemas/2/pipettePropertiesSchema.json", + "displayName": "Flex 1-Channel 50 μL", + "model": "p50", + "displayCategory": "FLEX", + "pickUpTipConfigurations": { + "pressFit": { + "presses": 1, + "speedByTipCount": { + "1": 10.0 + }, + "increment": 0.0, + "distanceByTipCount": { + "1": 13.0 + }, + "currentByTipCount": { + "1": 0.2 + } + } + }, + "dropTipConfigurations": { + "plungerEject": { + "current": 1.0, + "speed": 15 + } + }, + "plungerMotorConfigurations": { + "idle": 0.3, + "run": 1.0 + }, + "plungerPositionsConfigurations": { + "default": { + "top": 0.0, + "bottom": 71.5, + "blowout": 76.5, + "drop": 90.5 + }, + "lowVolumeDefault": { + "top": 0.0, + "bottom": 61.5, + "blowout": 76.5, + "drop": 90.5 + } + }, + "availableSensors": { + "sensors": ["pressure", "capacitive", "environment"], + "pressure": { + "count": 1 + }, + "capacitive": { + "count": 1 + }, + "environment": { + "count": 1 + } + }, + "partialTipConfigurations": { + "partialTipSupported": false, + "availableConfigurations": null + }, + "backCompatNames": [], + "channels": 1, + "shaftDiameter": 1.0, + "shaftULperMM": 0.785, + "backlashDistance": 0.1, + "quirks": [], + "plungerHomingConfigurations": { + "current": 1.0, + "speed": 30 + } +} diff --git a/shared-data/pipette/definitions/2/geometry/ninety_six_channel/p1000/3_6.json b/shared-data/pipette/definitions/2/geometry/ninety_six_channel/p1000/3_6.json new file mode 100644 index 00000000000..da209a72907 --- /dev/null +++ b/shared-data/pipette/definitions/2/geometry/ninety_six_channel/p1000/3_6.json @@ -0,0 +1,295 @@ +{ + "$otSharedSchema": "#/pipette/schemas/2/pipetteGeometrySchema.json", + "pathTo3D": "pipette/definitions/2/geometry/ninety_six_channel/p1000/placeholder.gltf", + "nozzleOffset": [-36.0, -25.5, -259.15], + "pipetteBoundingBoxOffsets": { + "backLeftCorner": [-67.0, -3.5, -259.15], + "frontRightCorner": [94.0, -113.0, -259.15] + }, + "orderedRows": [ + { + "key": "A", + "orderedNozzles": [ + "A1", + "A2", + "A3", + "A4", + "A5", + "A6", + "A7", + "A8", + "A9", + "A10", + "A11", + "A12" + ] + }, + { + "key": "B", + "orderedNozzles": [ + "B1", + "B2", + "B3", + "B4", + "B5", + "B6", + "B7", + "B8", + "B9", + "B10", + "B11", + "B12" + ] + }, + { + "key": "C", + "orderedNozzles": [ + "C1", + "C2", + "C3", + "C4", + "C5", + "C6", + "C7", + "C8", + "C9", + "C10", + "C11", + "C12" + ] + }, + { + "key": "D", + "orderedNozzles": [ + "D1", + "D2", + "D3", + "D4", + "D5", + "D6", + "D7", + "D8", + "D9", + "D10", + "D11", + "D12" + ] + }, + { + "key": "E", + "orderedNozzles": [ + "E1", + "E2", + "E3", + "E4", + "E5", + "E6", + "E7", + "E8", + "E9", + "E10", + "E11", + "E12" + ] + }, + { + "key": "F", + "orderedNozzles": [ + "F1", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + "F8", + "F9", + "F10", + "F11", + "F12" + ] + }, + { + "key": "G", + "orderedNozzles": [ + "G1", + "G2", + "G3", + "G4", + "G5", + "G6", + "G7", + "G8", + "G9", + "G10", + "G11", + "G12" + ] + }, + { + "key": "H", + "orderedNozzles": [ + "H1", + "H2", + "H3", + "H4", + "H5", + "H6", + "H7", + "H8", + "H9", + "H10", + "H11", + "H12" + ] + } + ], + "orderedColumns": [ + { + "key": "1", + "orderedNozzles": ["A1", "B1", "C1", "D1", "E1", "F1", "G1", "H1"] + }, + { + "key": "2", + "orderedNozzles": ["A2", "B2", "C2", "D2", "E2", "F2", "G2", "H2"] + }, + { + "key": "3", + "orderedNozzles": ["A3", "B3", "C3", "D3", "E3", "F3", "G3", "H3"] + }, + { + "key": "4", + "orderedNozzles": ["A4", "B4", "C4", "D4", "E4", "F4", "G4", "H4"] + }, + { + "key": "5", + "orderedNozzles": ["A5", "B5", "C5", "D5", "E5", "F5", "G5", "H5"] + }, + { + "key": "6", + "orderedNozzles": ["A6", "B6", "C6", "D6", "E6", "F6", "G6", "H6"] + }, + { + "key": "7", + "orderedNozzles": ["A7", "B7", "C7", "D7", "E7", "F7", "G7", "H7"] + }, + { + "key": "8", + "orderedNozzles": ["A8", "B8", "C8", "D8", "E8", "F8", "G8", "H8"] + }, + { + "key": "9", + "orderedNozzles": ["A9", "B9", "C9", "D9", "E9", "F9", "G9", "H9"] + }, + { + "key": "10", + "orderedNozzles": ["A10", "B10", "C10", "D10", "E10", "F10", "G10", "H10"] + }, + { + "key": "11", + "orderedNozzles": ["A11", "B11", "C11", "D11", "E11", "F11", "G11", "H11"] + }, + { + "key": "12", + "orderedNozzles": ["A12", "B12", "C12", "D12", "E12", "F12", "G12", "H12"] + } + ], + "nozzleMap": { + "A1": [-36.0, -25.5, -259.15], + "A2": [-27.0, -25.5, -259.15], + "A3": [-18.0, -25.5, -259.15], + "A4": [-9.0, -25.5, -259.15], + "A5": [0.0, -25.5, -259.15], + "A6": [9.0, -25.5, -259.15], + "A7": [18.0, -25.5, -259.15], + "A8": [27.0, -25.5, -259.15], + "A9": [36.0, -25.5, -259.15], + "A10": [45.0, -25.5, -259.15], + "A11": [54.0, -25.5, -259.15], + "A12": [63.0, -25.5, -259.15], + "B1": [-36.0, -34.5, -259.15], + "B2": [-27.0, -34.5, -259.15], + "B3": [-18.0, -34.5, -259.15], + "B4": [-9.0, -34.5, -259.15], + "B5": [0.0, -34.5, -259.15], + "B6": [9.0, -34.5, -259.15], + "B7": [18.0, -34.5, -259.15], + "B8": [27.0, -34.5, -259.15], + "B9": [36.0, -34.5, -259.15], + "B10": [45.0, -34.5, -259.15], + "B11": [54.0, -34.5, -259.15], + "B12": [63.0, -34.5, -259.15], + "C1": [-36.0, -43.5, -259.15], + "C2": [-27.0, -43.5, -259.15], + "C3": [-18.0, -43.5, -259.15], + "C4": [-9.0, -43.5, -259.15], + "C5": [0.0, -43.5, -259.15], + "C6": [9.0, -43.5, -259.15], + "C7": [18.0, -43.5, -259.15], + "C8": [27.0, -43.5, -259.15], + "C9": [36.0, -43.5, -259.15], + "C10": [45.0, -43.5, -259.15], + "C11": [54.0, -43.5, -259.15], + "C12": [63.0, -43.5, -259.15], + "D1": [-36.0, -52.5, -259.15], + "D2": [-27.0, -52.5, -259.15], + "D3": [-18.0, -52.5, -259.15], + "D4": [-9.0, -52.5, -259.15], + "D5": [0.0, -52.5, -259.15], + "D6": [9.0, -52.5, -259.15], + "D7": [18.0, -52.5, -259.15], + "D8": [27.0, -52.5, -259.15], + "D9": [36.0, -52.5, -259.15], + "D10": [45.0, -52.5, -259.15], + "D11": [54.0, -52.5, -259.15], + "D12": [63.0, -52.5, -259.15], + "E1": [-36.0, -61.5, -259.15], + "E2": [-27.0, -61.5, -259.15], + "E3": [-18.0, -61.5, -259.15], + "E4": [-9.0, -61.5, -259.15], + "E5": [0.0, -61.5, -259.15], + "E6": [9.0, -61.5, -259.15], + "E7": [18.0, -61.5, -259.15], + "E8": [27.0, -61.5, -259.15], + "E9": [36.0, -61.5, -259.15], + "E10": [45.0, -61.5, -259.15], + "E11": [54.0, -61.5, -259.15], + "E12": [63.0, -61.5, -259.15], + "F1": [-36.0, -70.5, -259.15], + "F2": [-27.0, -70.5, -259.15], + "F3": [-18.0, -70.5, -259.15], + "F4": [-9.0, -70.5, -259.15], + "F5": [0.0, -70.5, -259.15], + "F6": [9.0, -70.5, -259.15], + "F7": [18.0, -70.5, -259.15], + "F8": [27.0, -70.5, -259.15], + "F9": [36.0, -70.5, -259.15], + "F10": [45.0, -70.5, -259.15], + "F11": [54.0, -70.5, -259.15], + "F12": [63.0, -70.5, -259.15], + "G1": [-36.0, -79.5, -259.15], + "G2": [-27.0, -79.5, -259.15], + "G3": [-18.0, -79.5, -259.15], + "G4": [-9.0, -79.5, -259.15], + "G5": [0.0, -79.5, -259.15], + "G6": [9.0, -79.5, -259.15], + "G7": [18.0, -79.5, -259.15], + "G8": [27.0, -79.5, -259.15], + "G9": [36.0, -79.5, -259.15], + "G10": [45.0, -79.5, -259.15], + "G11": [54.0, -79.5, -259.15], + "G12": [63.0, -79.5, -259.15], + "H1": [-36.0, -88.5, -259.15], + "H2": [-27.0, -88.5, -259.15], + "H3": [-18.0, -88.5, -259.15], + "H4": [-9.0, -88.5, -259.15], + "H5": [0.0, -88.5, -259.15], + "H6": [9.0, -88.5, -259.15], + "H7": [18.0, -88.5, -259.15], + "H8": [27.0, -88.5, -259.15], + "H9": [36.0, -88.5, -259.15], + "H10": [45.0, -88.5, -259.15], + "H11": [54.0, -88.5, -259.15], + "H12": [63.0, -88.5, -259.15] + } +} diff --git a/shared-data/pipette/definitions/2/geometry/single_channel/p50/3_6.json b/shared-data/pipette/definitions/2/geometry/single_channel/p50/3_6.json new file mode 100644 index 00000000000..ca5180c4415 --- /dev/null +++ b/shared-data/pipette/definitions/2/geometry/single_channel/p50/3_6.json @@ -0,0 +1,14 @@ +{ + "$otSharedSchema": "#/pipette/schemas/2/pipetteGeometrySchema.json", + "pathTo3D": "pipette/definitions/2/geometry/single_channel/p50/placeholder.gltf", + "nozzleOffset": [-8.0, -22.0, -259.15], + "pipetteBoundingBoxOffsets": { + "backLeftCorner": [-8.0, -22.0, -259.15], + "frontRightCorner": [-8.0, -22.0, -259.15] + }, + "orderedRows": [{ "key": "A", "orderedNozzles": ["A1"] }], + "orderedColumns": [{ "key": "1", "orderedNozzles": ["A1"] }], + "nozzleMap": { + "A1": [-8.0, -22.0, -259.15] + } +} diff --git a/shared-data/pipette/definitions/2/liquid/eight_channel/p1000/default/3_3.json b/shared-data/pipette/definitions/2/liquid/eight_channel/p1000/default/3_3.json index 12736030d8e..fd4f29a83bb 100644 --- a/shared-data/pipette/definitions/2/liquid/eight_channel/p1000/default/3_3.json +++ b/shared-data/pipette/definitions/2/liquid/eight_channel/p1000/default/3_3.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t50": { + "uiMaxFlowRate": 808.3, "defaultAspirateFlowRate": { "default": 6, "valuesByApiLevel": { "2.14": 6 } @@ -116,6 +117,7 @@ "defaultPushOutVolume": 7 }, "t200": { + "uiMaxFlowRate": 905.7, "defaultAspirateFlowRate": { "default": 80, "valuesByApiLevel": { "2.14": 80 } @@ -228,6 +230,7 @@ "defaultPushOutVolume": 5 }, "t1000": { + "uiMaxFlowRate": 787.7, "defaultAspirateFlowRate": { "default": 160, "valuesByApiLevel": { "2.14": 160 } diff --git a/shared-data/pipette/definitions/2/liquid/eight_channel/p1000/default/3_4.json b/shared-data/pipette/definitions/2/liquid/eight_channel/p1000/default/3_4.json index ae95738fb09..dcc9d533490 100644 --- a/shared-data/pipette/definitions/2/liquid/eight_channel/p1000/default/3_4.json +++ b/shared-data/pipette/definitions/2/liquid/eight_channel/p1000/default/3_4.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t50": { + "uiMaxFlowRate": 808.3, "defaultAspirateFlowRate": { "default": 478, "valuesByApiLevel": { "2.14": 478 } @@ -116,6 +117,7 @@ "defaultPushOutVolume": 7 }, "t200": { + "uiMaxFlowRate": 905.7, "defaultAspirateFlowRate": { "default": 716, "valuesByApiLevel": { "2.14": 716 } @@ -228,6 +230,7 @@ "defaultPushOutVolume": 5 }, "t1000": { + "uiMaxFlowRate": 787.7, "defaultAspirateFlowRate": { "default": 716, "valuesByApiLevel": { "2.14": 716 } diff --git a/shared-data/pipette/definitions/2/liquid/eight_channel/p1000/default/3_5.json b/shared-data/pipette/definitions/2/liquid/eight_channel/p1000/default/3_5.json index 1906adc8372..83026842153 100644 --- a/shared-data/pipette/definitions/2/liquid/eight_channel/p1000/default/3_5.json +++ b/shared-data/pipette/definitions/2/liquid/eight_channel/p1000/default/3_5.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t50": { + "uiMaxFlowRate": 802.9, "defaultAspirateFlowRate": { "default": 478, "valuesByApiLevel": { "2.14": 478 } @@ -82,6 +83,7 @@ "defaultPushOutVolume": 7 }, "t200": { + "uiMaxFlowRate": 847.9, "defaultAspirateFlowRate": { "default": 716, "valuesByApiLevel": { "2.14": 716 } @@ -160,6 +162,7 @@ "defaultPushOutVolume": 5 }, "t1000": { + "uiMaxFlowRate": 744.6, "defaultAspirateFlowRate": { "default": 716, "valuesByApiLevel": { "2.14": 716 } diff --git a/shared-data/pipette/definitions/2/liquid/eight_channel/p20/default/2_1.json b/shared-data/pipette/definitions/2/liquid/eight_channel/p20/default/2_1.json index 22950b76875..aa83a2e5bda 100644 --- a/shared-data/pipette/definitions/2/liquid/eight_channel/p20/default/2_1.json +++ b/shared-data/pipette/definitions/2/liquid/eight_channel/p20/default/2_1.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t20": { + "uiMaxFlowRate": 25, "defaultAspirateFlowRate": { "default": 7.6, "valuesByApiLevel": { "2.0": 7.6 } @@ -86,6 +87,7 @@ "defaultPushOutVolume": 0 }, "t10": { + "uiMaxFlowRate": 23, "defaultAspirateFlowRate": { "default": 7.6, "valuesByApiLevel": { "2.0": 7.6 } diff --git a/shared-data/pipette/definitions/2/liquid/eight_channel/p300/default/2_1.json b/shared-data/pipette/definitions/2/liquid/eight_channel/p300/default/2_1.json index a7d91165db7..4fee623f602 100644 --- a/shared-data/pipette/definitions/2/liquid/eight_channel/p300/default/2_1.json +++ b/shared-data/pipette/definitions/2/liquid/eight_channel/p300/default/2_1.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t200": { + "uiMaxFlowRate": 335.3, "defaultAspirateFlowRate": { "default": 94, "valuesByApiLevel": { "2.0": 94 } @@ -89,6 +90,7 @@ "defaultPushOutVolume": 0 }, "t300": { + "uiMaxFlowRate": 335.3, "defaultAspirateFlowRate": { "default": 94, "valuesByApiLevel": { "2.0": 94 } diff --git a/shared-data/pipette/definitions/2/liquid/eight_channel/p50/default/3_3.json b/shared-data/pipette/definitions/2/liquid/eight_channel/p50/default/3_3.json index ac12e0bea1e..38a4b01df80 100644 --- a/shared-data/pipette/definitions/2/liquid/eight_channel/p50/default/3_3.json +++ b/shared-data/pipette/definitions/2/liquid/eight_channel/p50/default/3_3.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t50": { + "uiMaxFlowRate": 46.8, "defaultAspirateFlowRate": { "default": 8, "valuesByApiLevel": { "2.14": 8 } diff --git a/shared-data/pipette/definitions/2/liquid/eight_channel/p50/default/3_4.json b/shared-data/pipette/definitions/2/liquid/eight_channel/p50/default/3_4.json index 352f61bae30..32131ee1982 100644 --- a/shared-data/pipette/definitions/2/liquid/eight_channel/p50/default/3_4.json +++ b/shared-data/pipette/definitions/2/liquid/eight_channel/p50/default/3_4.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t50": { + "uiMaxFlowRate": 46.8, "defaultAspirateFlowRate": { "default": 35, "valuesByApiLevel": { "2.14": 35 } diff --git a/shared-data/pipette/definitions/2/liquid/eight_channel/p50/default/3_5.json b/shared-data/pipette/definitions/2/liquid/eight_channel/p50/default/3_5.json index 49b2a7b549d..ca2a48db274 100644 --- a/shared-data/pipette/definitions/2/liquid/eight_channel/p50/default/3_5.json +++ b/shared-data/pipette/definitions/2/liquid/eight_channel/p50/default/3_5.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t50": { + "uiMaxFlowRate": 46.7, "defaultAspirateFlowRate": { "default": 35, "valuesByApiLevel": { "2.14": 35 } diff --git a/shared-data/pipette/definitions/2/liquid/eight_channel/p50/lowVolumeDefault/3_3.json b/shared-data/pipette/definitions/2/liquid/eight_channel/p50/lowVolumeDefault/3_3.json index 4e83eee5d81..cc629f28316 100644 --- a/shared-data/pipette/definitions/2/liquid/eight_channel/p50/lowVolumeDefault/3_3.json +++ b/shared-data/pipette/definitions/2/liquid/eight_channel/p50/lowVolumeDefault/3_3.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t50": { + "uiMaxFlowRate": 32.6, "defaultAspirateFlowRate": { "default": 8, "valuesByApiLevel": { "2.14": 8 } diff --git a/shared-data/pipette/definitions/2/liquid/eight_channel/p50/lowVolumeDefault/3_4.json b/shared-data/pipette/definitions/2/liquid/eight_channel/p50/lowVolumeDefault/3_4.json index 881e9583aa5..0e9284b04e6 100644 --- a/shared-data/pipette/definitions/2/liquid/eight_channel/p50/lowVolumeDefault/3_4.json +++ b/shared-data/pipette/definitions/2/liquid/eight_channel/p50/lowVolumeDefault/3_4.json @@ -2,17 +2,18 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t50": { + "uiMaxFlowRate": 32.6, "defaultAspirateFlowRate": { - "default": 35, - "valuesByApiLevel": { "2.14": 35 } + "default": 32.6, + "valuesByApiLevel": { "2.14": 32.6 } }, "defaultDispenseFlowRate": { - "default": 57, - "valuesByApiLevel": { "2.14": 57 } + "default": 32.6, + "valuesByApiLevel": { "2.14": 32.6 } }, "defaultBlowOutFlowRate": { - "default": 57, - "valuesByApiLevel": { "2.14": 57 } + "default": 32.6, + "valuesByApiLevel": { "2.14": 32.6 } }, "defaultFlowAcceleration": 1200.0, "defaultTipLength": 57.9, diff --git a/shared-data/pipette/definitions/2/liquid/eight_channel/p50/lowVolumeDefault/3_5.json b/shared-data/pipette/definitions/2/liquid/eight_channel/p50/lowVolumeDefault/3_5.json index 881e9583aa5..0e9284b04e6 100644 --- a/shared-data/pipette/definitions/2/liquid/eight_channel/p50/lowVolumeDefault/3_5.json +++ b/shared-data/pipette/definitions/2/liquid/eight_channel/p50/lowVolumeDefault/3_5.json @@ -2,17 +2,18 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t50": { + "uiMaxFlowRate": 32.6, "defaultAspirateFlowRate": { - "default": 35, - "valuesByApiLevel": { "2.14": 35 } + "default": 32.6, + "valuesByApiLevel": { "2.14": 32.6 } }, "defaultDispenseFlowRate": { - "default": 57, - "valuesByApiLevel": { "2.14": 57 } + "default": 32.6, + "valuesByApiLevel": { "2.14": 32.6 } }, "defaultBlowOutFlowRate": { - "default": 57, - "valuesByApiLevel": { "2.14": 57 } + "default": 32.6, + "valuesByApiLevel": { "2.14": 32.6 } }, "defaultFlowAcceleration": 1200.0, "defaultTipLength": 57.9, diff --git a/shared-data/pipette/definitions/2/liquid/ninety_six_channel/p1000/default/3_3.json b/shared-data/pipette/definitions/2/liquid/ninety_six_channel/p1000/default/3_3.json index 0f3f56f6494..899d08aeaee 100644 --- a/shared-data/pipette/definitions/2/liquid/ninety_six_channel/p1000/default/3_3.json +++ b/shared-data/pipette/definitions/2/liquid/ninety_six_channel/p1000/default/3_3.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t50": { + "uiMaxFlowRate": 189.1, "defaultAspirateFlowRate": { "default": 6, "valuesByApiLevel": { "2.14": 6 } @@ -56,6 +57,7 @@ "defaultPushOutVolume": 7 }, "t200": { + "uiMaxFlowRate": 185.1, "defaultAspirateFlowRate": { "default": 80, "valuesByApiLevel": { "2.14": 80 } @@ -108,6 +110,7 @@ "defaultPushOutVolume": 5 }, "t1000": { + "uiMaxFlowRate": 184.8, "defaultAspirateFlowRate": { "default": 160, "valuesByApiLevel": { "2.14": 160 } diff --git a/shared-data/pipette/definitions/2/liquid/ninety_six_channel/p1000/default/3_4.json b/shared-data/pipette/definitions/2/liquid/ninety_six_channel/p1000/default/3_4.json index 0f3f56f6494..899d08aeaee 100644 --- a/shared-data/pipette/definitions/2/liquid/ninety_six_channel/p1000/default/3_4.json +++ b/shared-data/pipette/definitions/2/liquid/ninety_six_channel/p1000/default/3_4.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t50": { + "uiMaxFlowRate": 189.1, "defaultAspirateFlowRate": { "default": 6, "valuesByApiLevel": { "2.14": 6 } @@ -56,6 +57,7 @@ "defaultPushOutVolume": 7 }, "t200": { + "uiMaxFlowRate": 185.1, "defaultAspirateFlowRate": { "default": 80, "valuesByApiLevel": { "2.14": 80 } @@ -108,6 +110,7 @@ "defaultPushOutVolume": 5 }, "t1000": { + "uiMaxFlowRate": 184.8, "defaultAspirateFlowRate": { "default": 160, "valuesByApiLevel": { "2.14": 160 } diff --git a/shared-data/pipette/definitions/2/liquid/ninety_six_channel/p1000/default/3_5.json b/shared-data/pipette/definitions/2/liquid/ninety_six_channel/p1000/default/3_5.json index 0f3f56f6494..1b9c88edf92 100644 --- a/shared-data/pipette/definitions/2/liquid/ninety_six_channel/p1000/default/3_5.json +++ b/shared-data/pipette/definitions/2/liquid/ninety_six_channel/p1000/default/3_5.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t50": { + "uiMaxFlowRate": 189.1, "defaultAspirateFlowRate": { "default": 6, "valuesByApiLevel": { "2.14": 6 } @@ -56,6 +57,7 @@ "defaultPushOutVolume": 7 }, "t200": { + "uiMaxFlowRate": 185.1, "defaultAspirateFlowRate": { "default": 80, "valuesByApiLevel": { "2.14": 80 } @@ -108,6 +110,7 @@ "defaultPushOutVolume": 5 }, "t1000": { + "uiMaxFlowRate": 185.1, "defaultAspirateFlowRate": { "default": 160, "valuesByApiLevel": { "2.14": 160 } diff --git a/shared-data/pipette/definitions/2/liquid/ninety_six_channel/p1000/default/3_6.json b/shared-data/pipette/definitions/2/liquid/ninety_six_channel/p1000/default/3_6.json new file mode 100644 index 00000000000..cd27abd81f0 --- /dev/null +++ b/shared-data/pipette/definitions/2/liquid/ninety_six_channel/p1000/default/3_6.json @@ -0,0 +1,191 @@ +{ + "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", + "supportedTips": { + "t50": { + "uiMaxFlowRate": 194, + "defaultAspirateFlowRate": { + "default": 6, + "valuesByApiLevel": { "2.14": 6 } + }, + "defaultDispenseFlowRate": { + "default": 6, + "valuesByApiLevel": { "2.14": 6 } + }, + "defaultBlowOutFlowRate": { + "default": 80, + "valuesByApiLevel": { "2.14": 80 } + }, + "defaultFlowAcceleration": 16000.0, + "defaultTipLength": 57.9, + "defaultReturnTipHeight": 0.2, + "aspirate": { + "default": { + "1": [ + [1.9733, 2.7039, 5.1258], + [2.88, 1.0915, 8.3077], + [3.7642, 0.5906, 9.7502], + [4.9783, 1.0072, 8.1822], + [5.9342, 0.2998, 11.7038], + [6.8708, 0.1887, 12.3626], + [7.8092, 0.1497, 12.631], + [8.7525, 0.1275, 12.804], + [13.4575, 0.0741, 13.2718], + [22.8675, 0.0296, 13.87], + [37.0442, 0.0128, 14.2551], + [55.4792, -0.0013, 14.7754] + ] + } + }, + "dispense": { + "default": { + "1": [ + [1.9733, 2.7039, 5.1258], + [2.88, 1.0915, 8.3077], + [3.7642, 0.5906, 9.7502], + [4.9783, 1.0072, 8.1822], + [5.9342, 0.2998, 11.7038], + [6.8708, 0.1887, 12.3626], + [7.8092, 0.1497, 12.631], + [8.7525, 0.1275, 12.804], + [13.4575, 0.0741, 13.2718], + [22.8675, 0.0296, 13.87], + [37.0442, 0.0128, 14.2551], + [55.4792, -0.0013, 14.7754] + ] + } + }, + "defaultPushOutVolume": 7 + }, + "t200": { + "uiMaxFlowRate": 194, + "defaultAspirateFlowRate": { + "default": 80, + "valuesByApiLevel": { "2.14": 80 } + }, + "defaultDispenseFlowRate": { + "default": 80, + "valuesByApiLevel": { "2.14": 80 } + }, + "defaultBlowOutFlowRate": { + "default": 80, + "valuesByApiLevel": { "2.14": 80 } + }, + "defaultFlowAcceleration": 16000.0, + "defaultTipLength": 58.35, + "defaultReturnTipHeight": 0.2, + "aspirate": { + "default": { + "1": [ + [1.9331, 3.4604, 3.5588], + [2.9808, 1.5307, 7.2892], + [3.9869, 0.825, 9.3926], + [4.9762, 0.5141, 10.6323], + [5.9431, 0.3232, 11.5819], + [6.9223, 0.2644, 11.9317], + [7.8877, 0.1832, 12.4935], + [8.8562, 0.1512, 12.7463], + [47.7169, 0.0281, 13.836], + [95.63, 0.0007, 15.147], + [211.1169, 0.0005, 15.1655] + ] + } + }, + "dispense": { + "default": { + "1": [ + [1.9331, 3.4604, 3.5588], + [2.9808, 1.5307, 7.2892], + [3.9869, 0.825, 9.3926], + [4.9762, 0.5141, 10.6323], + [5.9431, 0.3232, 11.5819], + [6.9223, 0.2644, 11.9317], + [7.8877, 0.1832, 12.4935], + [8.8562, 0.1512, 12.7463], + [47.7169, 0.0281, 13.836], + [95.63, 0.0007, 15.147], + [211.1169, 0.0005, 15.1655] + ] + } + }, + "defaultPushOutVolume": 5 + }, + "t1000": { + "uiMaxFlowRate": 187.2, + "defaultAspirateFlowRate": { + "default": 160, + "valuesByApiLevel": { "2.14": 160 } + }, + "defaultDispenseFlowRate": { + "default": 160, + "valuesByApiLevel": { "2.14": 160 } + }, + "defaultBlowOutFlowRate": { + "default": 80, + "valuesByApiLevel": { "2.14": 80 } + }, + "defaultFlowAcceleration": 16000.0, + "defaultTipLength": 95.6, + "defaultReturnTipHeight": 0.2, + "aspirate": { + "default": { + "1": [ + [3.9, 1.789, 5.4283], + [5.6991, 0.3019, 11.2278], + [8.5155, 0.2111, 11.7453], + [13.1482, 0.0858, 12.8124], + [17.8909, 0.0604, 13.1472], + [46.0982, 0.0155, 13.9505], + [93.5618, 0.0046, 14.4523], + [112.5991, 0.0023, 14.6687], + [189.5555, 0.002, 14.7035], + [305.5891, 0.001, 14.887], + [431.2836, 0.0004, 15.055], + [625.0209, 0.0003, 15.1309], + [818.6909, 0.0001, 15.2112], + [963.9909, 0.0001, 15.2445], + [992.0791, -0.0005, 15.7723], + [1012.2118, 0.0007, 14.6701], + [1037.1873, 0.0005, 14.8072] + ] + } + }, + "dispense": { + "default": { + "1": [ + [3.9, 1.789, 5.4283], + [5.6991, 0.3019, 11.2278], + [8.5155, 0.2111, 11.7453], + [13.1482, 0.0858, 12.8124], + [17.8909, 0.0604, 13.1472], + [46.0982, 0.0155, 13.9505], + [93.5618, 0.0046, 14.4523], + [112.5991, 0.0023, 14.6687], + [189.5555, 0.002, 14.7035], + [305.5891, 0.001, 14.887], + [431.2836, 0.0004, 15.055], + [625.0209, 0.0003, 15.1309], + [818.6909, 0.0001, 15.2112], + [963.9909, 0.0001, 15.2445], + [992.0791, -0.0005, 15.7723], + [1012.2118, 0.0007, 14.6701], + [1037.1873, 0.0005, 14.8072] + ] + } + }, + "defaultPushOutVolume": 20 + } + }, + "defaultTipOverlapDictionary": { + "default": 10.5, + "opentrons/opentrons_flex_96_tiprack_50ul/1": 10.5, + "opentrons/opentrons_flex_96_tiprack_1000ul/1": 10.5, + "opentrons/opentrons_flex_96_tiprack_200ul/1": 10.5 + }, + "maxVolume": 1000, + "minVolume": 5, + "defaultTipracks": [ + "opentrons/opentrons_flex_96_tiprack_1000ul/1", + "opentrons/opentrons_flex_96_tiprack_200ul/1", + "opentrons/opentrons_flex_96_tiprack_50ul/1" + ] +} diff --git a/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/2_1.json b/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/2_1.json index 9a281ac618c..46563177001 100644 --- a/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/2_1.json +++ b/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/2_1.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t1000": { + "uiMaxFlowRate": 1018.6, "defaultAspirateFlowRate": { "default": 274.7, "valuesByApiLevel": { "2.0": 137.35, "2.6": 274.7 } diff --git a/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/2_2.json b/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/2_2.json index bc51e5751d9..bfb9c6e83e8 100644 --- a/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/2_2.json +++ b/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/2_2.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t1000": { + "uiMaxFlowRate": 1020.7, "defaultAspirateFlowRate": { "default": 274.7, "valuesByApiLevel": { "2.0": 137.35, "2.6": 274.7 } diff --git a/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/3_3.json b/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/3_3.json index 476cb96cc69..e4e765c999c 100644 --- a/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/3_3.json +++ b/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/3_3.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t50": { + "uiMaxFlowRate": 808.3, "defaultAspirateFlowRate": { "default": 6, "valuesByApiLevel": { "2.14": 6 } @@ -116,6 +117,7 @@ "defaultPushOutVolume": 7 }, "t200": { + "uiMaxFlowRate": 905.7, "defaultAspirateFlowRate": { "default": 80, "valuesByApiLevel": { "2.14": 80 } @@ -228,6 +230,7 @@ "defaultPushOutVolume": 5 }, "t1000": { + "uiMaxFlowRate": 787.7, "defaultAspirateFlowRate": { "default": 160, "valuesByApiLevel": { "2.14": 160 } diff --git a/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/3_4.json b/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/3_4.json index 28226b82e4d..f48e41f37f2 100644 --- a/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/3_4.json +++ b/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/3_4.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t50": { + "uiMaxFlowRate": 762.1, "defaultAspirateFlowRate": { "default": 478, "valuesByApiLevel": { "2.14": 478 } @@ -90,6 +91,7 @@ "defaultPushOutVolume": 7 }, "t200": { + "uiMaxFlowRate": 745, "defaultAspirateFlowRate": { "default": 716, "valuesByApiLevel": { "2.14": 716 } @@ -178,6 +180,7 @@ "defaultPushOutVolume": 5 }, "t1000": { + "uiMaxFlowRate": 763.3, "defaultAspirateFlowRate": { "default": 716, "valuesByApiLevel": { "2.14": 716 } diff --git a/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/3_5.json b/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/3_5.json index 65456da3a9d..9c939ba9c7c 100644 --- a/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/3_5.json +++ b/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/3_5.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t50": { + "uiMaxFlowRate": 785.2, "defaultAspirateFlowRate": { "default": 478, "valuesByApiLevel": { "2.14": 478 } @@ -70,6 +71,7 @@ "defaultPushOutVolume": 7 }, "t200": { + "uiMaxFlowRate": 802.5, "defaultAspirateFlowRate": { "default": 716, "valuesByApiLevel": { "2.14": 716 } @@ -128,6 +130,7 @@ "defaultPushOutVolume": 5 }, "t1000": { + "uiMaxFlowRate": 753.5, "defaultAspirateFlowRate": { "default": 716, "valuesByApiLevel": { "2.14": 716 } diff --git a/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/3_6.json b/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/3_6.json index 29caae1b15b..72187981c26 100644 --- a/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/3_6.json +++ b/shared-data/pipette/definitions/2/liquid/single_channel/p1000/default/3_6.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t50": { + "uiMaxFlowRate": 785.2, "defaultAspirateFlowRate": { "default": 478, "valuesByApiLevel": { "2.14": 478 } @@ -70,6 +71,7 @@ "defaultPushOutVolume": 7 }, "t200": { + "uiMaxFlowRate": 802.5, "defaultAspirateFlowRate": { "default": 716, "valuesByApiLevel": { "2.14": 716 } @@ -128,6 +130,7 @@ "defaultPushOutVolume": 5 }, "t1000": { + "uiMaxFlowRate": 727.3, "defaultAspirateFlowRate": { "default": 716, "valuesByApiLevel": { "2.14": 716 } diff --git a/shared-data/pipette/definitions/2/liquid/single_channel/p20/default/2_1.json b/shared-data/pipette/definitions/2/liquid/single_channel/p20/default/2_1.json index 8acb156a2af..e10b9ba735d 100644 --- a/shared-data/pipette/definitions/2/liquid/single_channel/p20/default/2_1.json +++ b/shared-data/pipette/definitions/2/liquid/single_channel/p20/default/2_1.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t20": { + "uiMaxFlowRate": 25.3, "defaultAspirateFlowRate": { "default": 3.78, "valuesByApiLevel": { "2.0": 3.78, "2.6": 7.56 } @@ -146,6 +147,7 @@ "defaultPushOutVolume": 0 }, "t10": { + "uiMaxFlowRate": 25.3, "defaultAspirateFlowRate": { "default": 3.78, "valuesByApiLevel": { "2.0": 3.78, "2.6": 7.56 } diff --git a/shared-data/pipette/definitions/2/liquid/single_channel/p20/default/2_2.json b/shared-data/pipette/definitions/2/liquid/single_channel/p20/default/2_2.json index 907d4546520..eba2ed05cb1 100644 --- a/shared-data/pipette/definitions/2/liquid/single_channel/p20/default/2_2.json +++ b/shared-data/pipette/definitions/2/liquid/single_channel/p20/default/2_2.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t20": { + "uiMaxFlowRate": 25, "defaultAspirateFlowRate": { "default": 3.78, "valuesByApiLevel": { "2.0": 3.78, "2.6": 7.56 } @@ -146,6 +147,7 @@ "defaultPushOutVolume": 0 }, "t10": { + "uiMaxFlowRate": 25, "defaultAspirateFlowRate": { "default": 3.78, "valuesByApiLevel": { "2.0": 3.78, "2.6": 7.56 } diff --git a/shared-data/pipette/definitions/2/liquid/single_channel/p300/default/2_1.json b/shared-data/pipette/definitions/2/liquid/single_channel/p300/default/2_1.json index 14b514edf8d..0478ea9c0e5 100644 --- a/shared-data/pipette/definitions/2/liquid/single_channel/p300/default/2_1.json +++ b/shared-data/pipette/definitions/2/liquid/single_channel/p300/default/2_1.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t200": { + "uiMaxFlowRate": 329.3, "defaultAspirateFlowRate": { "default": 46.43, "valuesByApiLevel": { "2.0": 46.43, "2.6": 92.86 } @@ -88,6 +89,7 @@ "defaultPushOutVolume": 0 }, "t300": { + "uiMaxFlowRate": 329.3, "defaultAspirateFlowRate": { "default": 46.43, "valuesByApiLevel": { "2.0": 46.43, "2.6": 92.86 } diff --git a/shared-data/pipette/definitions/2/liquid/single_channel/p50/default/3_3.json b/shared-data/pipette/definitions/2/liquid/single_channel/p50/default/3_3.json index f5492d8809a..a5d87c485ba 100644 --- a/shared-data/pipette/definitions/2/liquid/single_channel/p50/default/3_3.json +++ b/shared-data/pipette/definitions/2/liquid/single_channel/p50/default/3_3.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t50": { + "uiMaxFlowRate": 46.8, "defaultAspirateFlowRate": { "default": 8, "valuesByApiLevel": { "2.14": 8 } diff --git a/shared-data/pipette/definitions/2/liquid/single_channel/p50/default/3_4.json b/shared-data/pipette/definitions/2/liquid/single_channel/p50/default/3_4.json index df9fc3d784b..464eb213798 100644 --- a/shared-data/pipette/definitions/2/liquid/single_channel/p50/default/3_4.json +++ b/shared-data/pipette/definitions/2/liquid/single_channel/p50/default/3_4.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t50": { + "uiMaxFlowRate": 46.3, "defaultAspirateFlowRate": { "default": 35, "valuesByApiLevel": { "2.14": 35 } diff --git a/shared-data/pipette/definitions/2/liquid/single_channel/p50/default/3_5.json b/shared-data/pipette/definitions/2/liquid/single_channel/p50/default/3_5.json index c798ce421a6..2fca659b070 100644 --- a/shared-data/pipette/definitions/2/liquid/single_channel/p50/default/3_5.json +++ b/shared-data/pipette/definitions/2/liquid/single_channel/p50/default/3_5.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t50": { + "uiMaxFlowRate": 47, "defaultAspirateFlowRate": { "default": 35, "valuesByApiLevel": { "2.14": 35 } diff --git a/shared-data/pipette/definitions/2/liquid/single_channel/p50/default/3_6.json b/shared-data/pipette/definitions/2/liquid/single_channel/p50/default/3_6.json new file mode 100644 index 00000000000..2fca659b070 --- /dev/null +++ b/shared-data/pipette/definitions/2/liquid/single_channel/p50/default/3_6.json @@ -0,0 +1,85 @@ +{ + "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", + "supportedTips": { + "t50": { + "uiMaxFlowRate": 47, + "defaultAspirateFlowRate": { + "default": 35, + "valuesByApiLevel": { "2.14": 35 } + }, + "defaultDispenseFlowRate": { + "default": 57, + "valuesByApiLevel": { "2.14": 57 } + }, + "defaultBlowOutFlowRate": { + "default": 57, + "valuesByApiLevel": { "2.14": 57 } + }, + "defaultFlowAcceleration": 1200.0, + "defaultTipLength": 57.9, + "defaultReturnTipHeight": 0.71, + "aspirate": { + "default": { + "1": [ + [0.462, 0.5646, 0.0415], + [0.648, 0.3716, 0.1307], + [1.032, 0.2742, 0.1938], + [1.37, 0.1499, 0.3221], + [2.014, 0.1044, 0.3845], + [2.772, 0.0432, 0.5076], + [3.05, -0.0809, 0.8517], + [3.4, 0.0256, 0.5268], + [3.962, 0.0612, 0.4057], + [4.438, 0.0572, 0.4217], + [5.164, 0.018, 0.5955], + [5.966, 0.0095, 0.6393], + [7.38, 0.0075, 0.6514], + [9.128, 0.0049, 0.6705], + [10.16, 0.0033, 0.6854], + [13.812, 0.0024, 0.6948], + [27.204, 0.0008, 0.7165], + [50.614, 0.0002, 0.7328], + [53.046, -0.0005, 0.7676] + ] + } + }, + "dispense": { + "default": { + "1": [ + [0.462, 0.5646, 0.0415], + [0.648, 0.3716, 0.1307], + [1.032, 0.2742, 0.1938], + [1.37, 0.1499, 0.3221], + [2.014, 0.1044, 0.3845], + [2.772, 0.0432, 0.5076], + [3.05, -0.0809, 0.8517], + [3.4, 0.0256, 0.5268], + [3.962, 0.0612, 0.4057], + [4.438, 0.0572, 0.4217], + [5.164, 0.018, 0.5955], + [5.966, 0.0095, 0.6393], + [7.38, 0.0075, 0.6514], + [9.128, 0.0049, 0.6705], + [10.16, 0.0033, 0.6854], + [13.812, 0.0024, 0.6948], + [27.204, 0.0008, 0.7165], + [50.614, 0.0002, 0.7328], + [53.046, -0.0005, 0.7676] + ] + } + }, + "defaultPushOutVolume": 2 + } + }, + "defaultTipOverlapDictionary": { + "default": 10.5, + "opentrons/opentrons_flex_96_tiprack_50ul/1": 10.5, + "opentrons/opentrons_flex_96_filtertiprack_50ul/1": 10.5 + }, + "maxVolume": 50, + "minVolume": 5, + "defaultTipracks": [ + "opentrons/opentrons_flex_96_tiprack_50ul/1", + "opentrons/opentrons_flex_96_filtertiprack_50ul/1" + ] +} diff --git a/shared-data/pipette/definitions/2/liquid/single_channel/p50/lowVolumeDefault/3_3.json b/shared-data/pipette/definitions/2/liquid/single_channel/p50/lowVolumeDefault/3_3.json index 2a292477578..deae3998fe9 100644 --- a/shared-data/pipette/definitions/2/liquid/single_channel/p50/lowVolumeDefault/3_3.json +++ b/shared-data/pipette/definitions/2/liquid/single_channel/p50/lowVolumeDefault/3_3.json @@ -2,6 +2,7 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t50": { + "uiMaxFlowRate": 31.8, "defaultAspirateFlowRate": { "default": 8, "valuesByApiLevel": { "2.14": 8 } diff --git a/shared-data/pipette/definitions/2/liquid/single_channel/p50/lowVolumeDefault/3_4.json b/shared-data/pipette/definitions/2/liquid/single_channel/p50/lowVolumeDefault/3_4.json index 771ff88cf22..397dc63b230 100644 --- a/shared-data/pipette/definitions/2/liquid/single_channel/p50/lowVolumeDefault/3_4.json +++ b/shared-data/pipette/definitions/2/liquid/single_channel/p50/lowVolumeDefault/3_4.json @@ -2,17 +2,18 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t50": { + "uiMaxFlowRate": 31.8, "defaultAspirateFlowRate": { - "default": 35, - "valuesByApiLevel": { "2.14": 35 } + "default": 31.8, + "valuesByApiLevel": { "2.14": 31.8 } }, "defaultDispenseFlowRate": { - "default": 57, - "valuesByApiLevel": { "2.14": 57 } + "default": 31.8, + "valuesByApiLevel": { "2.14": 31.8 } }, "defaultBlowOutFlowRate": { - "default": 57, - "valuesByApiLevel": { "2.14": 57 } + "default": 31.8, + "valuesByApiLevel": { "2.14": 31.8 } }, "defaultFlowAcceleration": 1200.0, "defaultTipLength": 57.9, diff --git a/shared-data/pipette/definitions/2/liquid/single_channel/p50/lowVolumeDefault/3_5.json b/shared-data/pipette/definitions/2/liquid/single_channel/p50/lowVolumeDefault/3_5.json index 644d93354e8..e1b92133bd6 100644 --- a/shared-data/pipette/definitions/2/liquid/single_channel/p50/lowVolumeDefault/3_5.json +++ b/shared-data/pipette/definitions/2/liquid/single_channel/p50/lowVolumeDefault/3_5.json @@ -2,17 +2,18 @@ "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { "t50": { + "uiMaxFlowRate": 26.7, "defaultAspirateFlowRate": { - "default": 35, - "valuesByApiLevel": { "2.14": 35 } + "default": 26.7, + "valuesByApiLevel": { "2.14": 26.7 } }, "defaultDispenseFlowRate": { - "default": 57, - "valuesByApiLevel": { "2.14": 57 } + "default": 26.7, + "valuesByApiLevel": { "2.14": 26.7 } }, "defaultBlowOutFlowRate": { - "default": 57, - "valuesByApiLevel": { "2.14": 57 } + "default": 26.7, + "valuesByApiLevel": { "2.14": 26.7 } }, "defaultFlowAcceleration": 1200.0, "defaultTipLength": 57.9, diff --git a/shared-data/pipette/definitions/2/liquid/single_channel/p50/lowVolumeDefault/3_6.json b/shared-data/pipette/definitions/2/liquid/single_channel/p50/lowVolumeDefault/3_6.json new file mode 100644 index 00000000000..06b676081ca --- /dev/null +++ b/shared-data/pipette/definitions/2/liquid/single_channel/p50/lowVolumeDefault/3_6.json @@ -0,0 +1,81 @@ +{ + "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", + "supportedTips": { + "t50": { + "uiMaxFlowRate": 26.7, + "defaultAspirateFlowRate": { + "default": 35, + "valuesByApiLevel": { "2.14": 26.7 } + }, + "defaultDispenseFlowRate": { + "default": 57, + "valuesByApiLevel": { "2.14": 26.7 } + }, + "defaultBlowOutFlowRate": { + "default": 57, + "valuesByApiLevel": { "2.14": 26.7 } + }, + "defaultFlowAcceleration": 1200.0, + "defaultTipLength": 57.9, + "defaultReturnTipHeight": 0.71, + "aspirate": { + "default": { + "1": [ + [0.11, 0.207815, 0.040201], + [0.65, 0.43933, 0.014735], + [1.04, 0.256666, 0.133466], + [1.67, 0.147126, 0.247388], + [2.45, 0.078774, 0.361536], + [2.89, 0.042387, 0.450684], + [3.2, 0.014781, 0.530464], + [3.79, 0.071819, 0.347944], + [4.22, 0.051592, 0.424605], + [4.93, 0.021219, 0.552775], + [5.81, 0.023461, 0.541725], + [7.21, 0.008959, 0.625982], + [8.93, 0.005456, 0.651235], + [10.0, 0.007108, 0.636489], + [13.61, 0.002591, 0.681656], + [26.99, 0.001163, 0.701094], + [45.25, 0.000207, 0.726887] + ] + } + }, + "dispense": { + "default": { + "1": [ + [0.11, 0.207815, 0.040201], + [0.65, 0.43933, 0.014735], + [1.04, 0.256666, 0.133466], + [1.67, 0.147126, 0.247388], + [2.45, 0.078774, 0.361536], + [2.89, 0.042387, 0.450684], + [3.2, 0.014781, 0.530464], + [3.79, 0.071819, 0.347944], + [4.22, 0.051592, 0.424605], + [4.93, 0.021219, 0.552775], + [5.81, 0.023461, 0.541725], + [7.21, 0.008959, 0.625982], + [8.93, 0.005456, 0.651235], + [10.0, 0.007108, 0.636489], + [13.61, 0.002591, 0.681656], + [26.99, 0.001163, 0.701094], + [45.25, 0.000207, 0.726887] + ] + } + }, + "defaultPushOutVolume": 7 + } + }, + "defaultTipOverlapDictionary": { + "default": 10.5, + "opentrons/opentrons_flex_96_tiprack_50ul/1": 10.5, + "opentrons/opentrons_flex_96_filtertiprack_50ul/1": 10.5 + }, + "maxVolume": 30, + "minVolume": 1, + "defaultTipracks": [ + "opentrons/opentrons_flex_96_tiprack_50ul/1", + "opentrons/opentrons_flex_96_filtertiprack_50ul/1" + ] +} diff --git a/shared-data/pipette/schemas/2/pipetteLiquidPropertiesSchema.json b/shared-data/pipette/schemas/2/pipetteLiquidPropertiesSchema.json index f7a76e0cde0..a4ba8e659f1 100644 --- a/shared-data/pipette/schemas/2/pipetteLiquidPropertiesSchema.json +++ b/shared-data/pipette/schemas/2/pipetteLiquidPropertiesSchema.json @@ -68,13 +68,16 @@ ], "properties": { "defaultAspirateFlowRate": { - "$ref": "#/definitions/flowRate" + "$ref": "#/definitions/flowRate", + "$comment": "for lowVolumeDefault only, the flowRate matches the uiMaxFlowRate. This does not change physical behavior and was made for UI purposes" }, "defaultDispenseFlowRate": { - "$ref": "#/definitions/flowRate" + "$ref": "#/definitions/flowRate", + "$comment": "for lowVolumeDefault only, the flowRate matches the uiMaxFlowRate. This does not change physical behavior and was made for UI purposes" }, "defaultBlowOutFlowRate": { - "$ref": "#/definitions/flowRate" + "$ref": "#/definitions/flowRate", + "$comment": "for lowVolumeDefault only, the flowRate matches the uiMaxFlowRate. This does not change physical behavior and was made for UI purposes" }, "defaultFlowAcceleration": { "$ref": "#/definitions/positiveNumber" @@ -92,6 +95,11 @@ "dispense": { "type": "array", "items": { "$ref": "#/definitions/liquidHandlingSpecs" } + }, + "uiMaxFlowRate": { + "$ref": "#/definitions/positiveNumber", + "$comment": "To be used in frontend applications only since it is the limit-to-lowest-max", + "description": "An optional number to represent each pipette's supported tip max flow rate for aspirate and dispense. The limit is the lowest max flow rate given all the tip's volumes minus 2% for safety." } } } diff --git a/shared-data/protocol/fixtures/8/simpleFlexV8.json b/shared-data/protocol/fixtures/8/simpleFlexV8.json index 277d7e636fe..a188ab7c710 100644 --- a/shared-data/protocol/fixtures/8/simpleFlexV8.json +++ b/shared-data/protocol/fixtures/8/simpleFlexV8.json @@ -1220,8 +1220,8 @@ { "commandType": "loadModule", "params": { - "moduleId": "magneticModuleId", - "model": "magneticModuleV2", + "moduleId": "magneticBlockId", + "model": "magneticBlockV1", "location": { "slotName": "3" } } }, @@ -1254,7 +1254,7 @@ "namespace": "opentrons", "version": 1, "location": { - "moduleId": "magneticModuleId" + "moduleId": "magneticBlockId" }, "displayName": "Sample Collection Plate" } diff --git a/shared-data/python/opentrons_shared_data/deck/__init__.py b/shared-data/python/opentrons_shared_data/deck/__init__.py index e922d905ec2..24d56ad730e 100644 --- a/shared-data/python/opentrons_shared_data/deck/__init__.py +++ b/shared-data/python/opentrons_shared_data/deck/__init__.py @@ -15,9 +15,11 @@ DeckSchemaVersion3, DeckDefinitionV4, DeckSchemaVersion4, + DeckDefinitionV5, + DeckSchemaVersion5, ) -DEFAULT_DECK_DEFINITION_VERSION: Final = 4 +DEFAULT_DECK_DEFINITION_VERSION: Final = 5 class Offset(NamedTuple): @@ -38,6 +40,11 @@ class Offset(NamedTuple): } +@overload +def load(name: str, version: "DeckSchemaVersion5") -> "DeckDefinitionV5": + ... + + @overload def load(name: str, version: "DeckSchemaVersion4") -> "DeckDefinitionV4": ... diff --git a/shared-data/python/opentrons_shared_data/deck/dev_types.py b/shared-data/python/opentrons_shared_data/deck/dev_types.py index 06f372d73bd..4563ff10953 100644 --- a/shared-data/python/opentrons_shared_data/deck/dev_types.py +++ b/shared-data/python/opentrons_shared_data/deck/dev_types.py @@ -10,6 +10,7 @@ from ..module.dev_types import ModuleType +DeckSchemaVersion5 = Literal[5] DeckSchemaVersion4 = Literal[4] DeckSchemaVersion3 = Literal[3] DeckSchemaVersion2 = Literal[2] @@ -111,9 +112,11 @@ class Cutout(TypedDict): class CutoutFixture(TypedDict): id: str + expectOpentronsModuleSerialNumber: bool mayMountTo: List[str] displayName: str providesAddressableAreas: Dict[str, List[str]] + fixtureGroup: Dict[str, List[Dict[str, str]]] height: float @@ -176,4 +179,19 @@ class DeckDefinitionV4(_RequiredDeckDefinitionV4, total=False): gripperOffsets: Dict[str, GripperOffsets] -DeckDefinition = Union[DeckDefinitionV3, DeckDefinitionV4] +class _RequiredDeckDefinitionV5(TypedDict): + otId: str + schemaVersion: Literal[5] + cornerOffsetFromOrigin: List[float] + dimensions: List[float] + metadata: Metadata + robot: Robot + locations: LocationsV4 + cutoutFixtures: List[CutoutFixture] + + +class DeckDefinitionV5(_RequiredDeckDefinitionV5, total=False): + gripperOffsets: Dict[str, GripperOffsets] + + +DeckDefinition = Union[DeckDefinitionV3, DeckDefinitionV4, DeckDefinitionV5] diff --git a/shared-data/python/opentrons_shared_data/labware/labware_definition.py b/shared-data/python/opentrons_shared_data/labware/labware_definition.py index 203dba1455d..1b2e68040de 100644 --- a/shared-data/python/opentrons_shared_data/labware/labware_definition.py +++ b/shared-data/python/opentrons_shared_data/labware/labware_definition.py @@ -160,7 +160,7 @@ class Parameters(BaseModel): loadName: str = Field( ..., description="Name used to reference a labware definition", - pattern=SAFE_STRING_REGEX, + regex=SAFE_STRING_REGEX, ) isMagneticModuleCompatible: bool = Field( ..., @@ -262,7 +262,7 @@ class LabwareDefinition(BaseModel): "(eg myPlate v1/v2/v3). An incrementing integer", ge=1.0, ) - namespace: str = Field(..., pattern=SAFE_STRING_REGEX) + namespace: str = Field(..., regex=SAFE_STRING_REGEX) metadata: Metadata = Field( ..., description="Properties used for search and display" ) diff --git a/shared-data/python/opentrons_shared_data/performance/__init__.py b/shared-data/python/opentrons_shared_data/performance/__init__.py new file mode 100644 index 00000000000..8cdbffce690 --- /dev/null +++ b/shared-data/python/opentrons_shared_data/performance/__init__.py @@ -0,0 +1 @@ +"""Performance metrics.""" diff --git a/shared-data/python/opentrons_shared_data/performance/dev_types.py b/shared-data/python/opentrons_shared_data/performance/dev_types.py new file mode 100644 index 00000000000..15ddb5eba44 --- /dev/null +++ b/shared-data/python/opentrons_shared_data/performance/dev_types.py @@ -0,0 +1,77 @@ +"""Type definitions for performance tracking.""" +from dataclasses import dataclass +from typing import Protocol, Tuple, TypeVar, Callable, Any +from pathlib import Path +from enum import Enum + +F = TypeVar("F", bound=Callable[..., Any]) + + +class SupportsTracking(Protocol): + """Protocol for classes that support tracking of robot context.""" + + def __init__(self, storage_location: Path, should_track: bool) -> None: + """Initialize the tracker.""" + ... + + def track(self, state: "RobotContextState") -> Callable[[F], F]: + """Decorator to track the given state for the decorated function.""" + ... + + def store(self) -> None: + """Store the tracked data.""" + ... + + +class RobotContextState(Enum): + """Enum representing different states of a robot's operation context.""" + + STARTING_UP = 0, "STARTING_UP" + CALIBRATING = 1, "CALIBRATING" + ANALYZING_PROTOCOL = 2, "ANALYZING_PROTOCOL" + RUNNING_PROTOCOL = 3, "RUNNING_PROTOCOL" + SHUTTING_DOWN = 4, "SHUTTING_DOWN" + + def __init__(self, state_id: int, state_name: str) -> None: + """Initialize the enum member.""" + self.state_id = state_id + self.state_name = state_name + + @classmethod + def from_id(cls, state_id: int) -> "RobotContextState": + """Returns the enum member matching the given state ID. + + Args: + state_id: The ID of the state to retrieve. + + Returns: + RobotContextStates: The enum member corresponding to the given ID. + + Raises: + ValueError: If no matching state is found. + """ + for state in RobotContextState: + if state.state_id == state_id: + return state + raise ValueError(f"Invalid state id: {state_id}") + + +@dataclass(frozen=True) +class MetricsMetadata: + """Dataclass to store metadata about the metrics.""" + + name: str + storage_dir: Path + headers: Tuple[str, ...] + + @property + def data_file_location(self) -> Path: + """The location of the data file.""" + return self.storage_dir / self.name + + @property + def headers_file_location(self) -> Path: + """The location of the header file.""" + return self.data_file_location.with_stem( + self.data_file_location.stem + "_headers" + ) diff --git a/shared-data/python/opentrons_shared_data/pipette/pipette_definition.py b/shared-data/python/opentrons_shared_data/pipette/pipette_definition.py index d7f3435ec73..a7b43663884 100644 --- a/shared-data/python/opentrons_shared_data/pipette/pipette_definition.py +++ b/shared-data/python/opentrons_shared_data/pipette/pipette_definition.py @@ -72,17 +72,17 @@ class SupportedTipsDefinition(BaseModel): default_aspirate_flowrate: FlowRateDefinition = Field( ..., - description="The flowrate used in aspirations by default.", + description="The flowrate used in aspirations by default. For lowVolumeDefault only, the flowrate matches uiMaxFlowRate for ui purposes, it does not change physical behavior.", alias="defaultAspirateFlowRate", ) default_dispense_flowrate: FlowRateDefinition = Field( ..., - description="The flowrate used in dispenses by default.", + description="The flowrate used in dispenses by default. For lowVolumeDefault only, the flowrate matches uiMaxFlowRate for ui purposes, it does not change physical behavior.", alias="defaultDispenseFlowRate", ) default_blowout_flowrate: FlowRateDefinition = Field( ..., - description="The flowrate used in blowouts by default.", + description="The flowrate used in blowouts by default. For lowVolumeDefault only, the flowrate matches uiMaxFlowRate for ui purposes, it does not change physical behavior.", alias="defaultBlowOutFlowRate", ) default_flow_acceleration: float = Field( @@ -111,6 +111,13 @@ class SupportedTipsDefinition(BaseModel): description="The default volume for a push-out during dispense.", alias="defaultPushOutVolume", ) + ui_max_flow_rate: float = Field( + float( + "inf" + ), # some pipettes (GEN1, unreleased prototype models) don't have a max flow rate + description="The lowest volume max flow rate for a pipette's given supported tip, minus 2 percent for safety.", + alias="uiMaxFlowRate", + ) class MotorConfigurations(BaseModel): diff --git a/shared-data/python/opentrons_shared_data/pipette/pipette_load_name_conversions.py b/shared-data/python/opentrons_shared_data/pipette/pipette_load_name_conversions.py index e2122ed35fd..9853d58b4ae 100644 --- a/shared-data/python/opentrons_shared_data/pipette/pipette_load_name_conversions.py +++ b/shared-data/python/opentrons_shared_data/pipette/pipette_load_name_conversions.py @@ -1,6 +1,9 @@ import re -from typing import List, Optional, Union, cast +from functools import lru_cache +from typing import List, Optional, Union, cast, Literal, Tuple +from opentrons_shared_data import get_shared_data_root from .dev_types import PipetteModel, PipetteName + from .types import ( PipetteChannelType, PipetteModelType, @@ -106,26 +109,78 @@ def version_from_string(version: str) -> PipetteVersionType: return PipetteVersionType(major, minor) -def version_from_generation(pipette_name_list: List[str]) -> PipetteVersionType: - """Convert a string generation name to a py:obj:PipetteVersionType. +def get_channel_from_pipette_name(pipette_name_tuple: Tuple[str, ...]) -> str: + if "single" in pipette_name_tuple: + return "single_channel" + elif "96" in pipette_name_tuple: + return "ninety_six_channel" + else: + return "eight_channel" + + +def get_major_version_from_pipette_name( + pipette_name_tuple: Tuple[str, ...], +) -> Literal[1, 2, 3]: + # special-casing for 96-channel to return version 3 + if ( + "flex" in pipette_name_tuple + or "gen3" in pipette_name_tuple + or "96" in pipette_name_tuple + ): + return 3 + elif "gen2" in pipette_name_tuple: + return 2 + else: + return 1 + + +@lru_cache(4) +def version_from_generation(pipette_name_tuple: Tuple[str, ...]) -> PipetteVersionType: + """Convert pipetteName to a py:obj:PipetteVersionType - Pipette generations are strings in the format of "gen1" or "gen2", and - usually associated withe :py:data:PipetteName. + Given the pipette_name_tuple, cycle through each definition file path + and find the latest version (major and minor version combined) that + exists and return that version. Args: - pipette_name_list (List[str]): A list of strings from the separated by `_` - py:data:PipetteName. + pipette_name_tuple (Tuple[str, ...]): A tuple of strings from the separated + by `_` py:data:PipetteName. Returns: PipetteVersionType: A pipette version object. - """ - if "flex" in pipette_name_list or "gen3" in pipette_name_list: - return PipetteVersionType(3, 0) - elif "gen2" in pipette_name_list: - return PipetteVersionType(2, 0) - else: - return PipetteVersionType(1, 0) + major_version_from_pipette_name = get_major_version_from_pipette_name( + pipette_name_tuple + ) + model_from_pipette_name = pipette_name_tuple[0] + channel_from_pipette_name = get_channel_from_pipette_name(pipette_name_tuple) + + paths_to_validate = ( + get_shared_data_root() / "pipette" / "definitions" / "2" / "general" + ) + version_paths = ( + paths_to_validate / channel_from_pipette_name / model_from_pipette_name + ) + + highest_minor_version: PipetteModelMinorVersionType = 0 + + for version_file in version_paths.iterdir(): + version_list = version_file.stem.split("_") + major_version = version_list[0] + minor_version = version_list[1] + + # Check if the major version matches the expected major version + if major_version == str(major_version_from_pipette_name): + minor_version_int = int(minor_version) + minor_version_lit: PipetteModelMinorVersionType = cast( + PipetteModelMinorVersionType, minor_version_int + ) + + # Update the highest minor version if this version is higher + if highest_minor_version < minor_version_lit: + highest_minor_version = minor_version_lit + + return PipetteVersionType(major_version_from_pipette_name, highest_minor_version) def generation_from_string(pipette_name_list: List[str]) -> PipetteGenerationType: @@ -194,7 +249,12 @@ def convert_pipette_name( if provided_version: version = version_from_string(provided_version) else: - version = version_from_generation(split_pipette_name) + pipette_name_tuple: Tuple[str, str, str] = ( + split_pipette_name[0], + split_pipette_name[1], + split_pipette_name[2] if len(split_pipette_name) > 2 else "", + ) + version = version_from_generation(pipette_name_tuple) pipette_type = PipetteModelType[split_pipette_name[0]] diff --git a/api/src/opentrons/hardware_control/instruments/instrument_helpers.py b/shared-data/python/opentrons_shared_data/pipette/ul_per_mm.py similarity index 100% rename from api/src/opentrons/hardware_control/instruments/instrument_helpers.py rename to shared-data/python/opentrons_shared_data/pipette/ul_per_mm.py diff --git a/shared-data/python/setup.py b/shared-data/python/setup.py index 8aebebcb408..4e1720cb610 100644 --- a/shared-data/python/setup.py +++ b/shared-data/python/setup.py @@ -130,8 +130,6 @@ def get_version(): "Intended Audience :: Science/Research", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Topic :: Scientific/Engineering", ] @@ -151,7 +149,7 @@ def get_version(): if __name__ == "__main__": setup( - python_requires=">=3.8", + python_requires=">=3.10", name=DISTNAME, description=DESCRIPTION, license=LICENSE, diff --git a/shared-data/python/tests/deck/test_typechecks.py b/shared-data/python/tests/deck/test_typechecks.py index f021004b050..4e2406df0fa 100644 --- a/shared-data/python/tests/deck/test_typechecks.py +++ b/shared-data/python/tests/deck/test_typechecks.py @@ -5,7 +5,10 @@ list_names as list_deck_definition_names, load as load_deck_definition, ) -from opentrons_shared_data.deck.dev_types import DeckDefinitionV3, DeckDefinitionV4 +from opentrons_shared_data.deck.dev_types import ( + DeckDefinitionV3, + DeckDefinitionV5, +) @pytest.mark.parametrize("defname", list_deck_definition_names(version=3)) @@ -14,7 +17,7 @@ def test_v3_defs(defname): typeguard.check_type(defn, DeckDefinitionV3) -@pytest.mark.parametrize("defname", list_deck_definition_names(version=4)) -def test_v4_defs(defname): - defn = load_deck_definition(name=defname, version=4) - typeguard.check_type(defn, DeckDefinitionV4) +@pytest.mark.parametrize("defname", list_deck_definition_names(version=5)) +def test_v5_defs(defname): + defn = load_deck_definition(name=defname, version=5) + typeguard.check_type(defn, DeckDefinitionV5) diff --git a/shared-data/python/tests/labware/test_validations.py b/shared-data/python/tests/labware/test_validations.py new file mode 100644 index 00000000000..39052e5d150 --- /dev/null +++ b/shared-data/python/tests/labware/test_validations.py @@ -0,0 +1,21 @@ +import pytest + +from pydantic import ValidationError +from opentrons_shared_data.labware import load_definition +from opentrons_shared_data.labware.labware_definition import LabwareDefinition + +from . import get_ot_defs + + +def test_loadname_regex_applied() -> None: + defdict = load_definition(*get_ot_defs()[0]) + defdict["parameters"]["loadName"] = "ALSJHDAKJLA" + with pytest.raises(ValidationError): + LabwareDefinition.parse_obj(defdict) + + +def test_namespace_regex_applied() -> None: + defdict = load_definition(*get_ot_defs()[0]) + defdict["namespace"] = "ALSJHDAKJLA" + with pytest.raises(ValidationError): + LabwareDefinition.parse_obj(defdict) diff --git a/shared-data/python/tests/performance/__init__.py b/shared-data/python/tests/performance/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/shared-data/python/tests/performance/test_module_builds.py b/shared-data/python/tests/performance/test_module_builds.py new file mode 100644 index 00000000000..d52b5a59779 --- /dev/null +++ b/shared-data/python/tests/performance/test_module_builds.py @@ -0,0 +1,6 @@ +from pathlib import Path +from opentrons_shared_data.performance.dev_types import RobotContextState + + +def test_metrics_metadata(tmp_path: Path) -> None: + RobotContextState.ANALYZING_PROTOCOL diff --git a/shared-data/python/tests/pipette/test_max_flow_rates_per_volume.py b/shared-data/python/tests/pipette/test_max_flow_rates_per_volume.py new file mode 100644 index 00000000000..ff731ec0e3c --- /dev/null +++ b/shared-data/python/tests/pipette/test_max_flow_rates_per_volume.py @@ -0,0 +1,88 @@ +import os +import pytest +from typing import Iterator +from opentrons_shared_data import get_shared_data_root +from opentrons_shared_data.pipette.pipette_load_name_conversions import ( + convert_pipette_model, +) +from opentrons_shared_data.pipette.load_data import load_definition +from opentrons_shared_data.pipette.ul_per_mm import piecewise_volume_conversion + +from opentrons_shared_data.pipette.dev_types import PipetteModel +from opentrons_shared_data.pipette.pipette_definition import ( + ulPerMMDefinition, +) + + +DEFAULT_MAX_SPEED_HIGH_THROUGHPUT_OT3_AXIS_KIND_P = 15 +DEFAULT_MAX_SPEED_LOW_THROUGHPUT_OT3_AXIS_KIND_P = 70 +B_MAX_SPEED = 40 + + +def _get_plunger_max_speed(pipette_model: PipetteModel) -> float: + if "v2" in pipette_model: + return B_MAX_SPEED + else: + if "96" in pipette_model: + return DEFAULT_MAX_SPEED_HIGH_THROUGHPUT_OT3_AXIS_KIND_P + else: + return DEFAULT_MAX_SPEED_LOW_THROUGHPUT_OT3_AXIS_KIND_P + + +def _get_max_flow_rate_at_volume( + ul_per_mm_definition: ulPerMMDefinition, + pipette_model: PipetteModel, + volume: float, +) -> float: + max_speed = _get_plunger_max_speed(pipette_model) + map = list(ul_per_mm_definition.default.values())[-1] + ul_per_mm = piecewise_volume_conversion(volume, map) + return round(ul_per_mm * max_speed, 1) + + +def get_all_pipette_models() -> Iterator[PipetteModel]: + paths_to_validate = ( + get_shared_data_root() / "pipette" / "definitions" / "2" / "liquid" + ) + + _channel_model_str = { + "single_channel": "single", + "ninety_six_channel": "96", + "eight_channel": "multi", + } + assert os.listdir(paths_to_validate), "You have a path wrong" + for channel_dir in os.listdir(paths_to_validate): + for model_dir in os.listdir(paths_to_validate / channel_dir): + for liquid_file in os.listdir(paths_to_validate / channel_dir / model_dir): + for version_file in os.listdir( + paths_to_validate / channel_dir / model_dir / liquid_file + ): + version_list = version_file.split(".json")[0].split("_") + built_model: PipetteModel = PipetteModel( + f"{model_dir}_{_channel_model_str[channel_dir]}_v{version_list[0]}.{version_list[1]}" + ) + if version_list[0] != "1" and version_list[1] != "0": + yield built_model + + +@pytest.mark.parametrize("pipette", list(get_all_pipette_models())) +@pytest.mark.parametrize("action", ["aspirate", "dispense"]) +def test_max_flow_rates_per_volume(pipette: PipetteModel, action: str) -> None: + """Verify the max flow rate values for each pipette's supported tip is in range""" + pipette_model_version = convert_pipette_model(pipette) + definition = load_definition( + pipette_model_version.pipette_type, + pipette_model_version.pipette_channels, + pipette_model_version.pipette_version, + ) + for liquid_name, liquid_properties in definition.liquid_properties.items(): + for ( + tip_type, + supported_tip, + ) in liquid_properties.supported_tips.items(): + assert supported_tip.ui_max_flow_rate < _get_max_flow_rate_at_volume( + supported_tip.aspirate, pipette, liquid_properties.min_volume + ) + assert supported_tip.ui_max_flow_rate < _get_max_flow_rate_at_volume( + supported_tip.dispense, pipette, liquid_properties.min_volume + ) diff --git a/shared-data/python/tests/pipette/test_pipette_load_name_conversions.py b/shared-data/python/tests/pipette/test_pipette_load_name_conversions.py index 2cb589ba636..a62880429e1 100644 --- a/shared-data/python/tests/pipette/test_pipette_load_name_conversions.py +++ b/shared-data/python/tests/pipette/test_pipette_load_name_conversions.py @@ -103,7 +103,7 @@ def test_convert_pipette_model_provided_version( pc.PipetteModelVersionType( PipetteModelType.p1000, PipetteChannelType.EIGHT_CHANNEL, - PipetteVersionType(3, 0), + PipetteVersionType(3, 5), ), ], [ @@ -111,7 +111,7 @@ def test_convert_pipette_model_provided_version( pc.PipetteModelVersionType( PipetteModelType.p1000, PipetteChannelType.NINETY_SIX_CHANNEL, - PipetteVersionType(1, 0), + PipetteVersionType(3, 6), ), ], ], diff --git a/shared-data/webpack.config.js b/shared-data/webpack.config.js deleted file mode 100644 index 18aa6478319..00000000000 --- a/shared-data/webpack.config.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict' - -const path = require('path') -const webpackMerge = require('webpack-merge') -const { baseConfig } = require('@opentrons/webpack-config') - -const ENTRY_INDEX = path.join(__dirname, 'js/index.ts') -const OUTPUT_PATH = path.join(__dirname, 'lib') - -module.exports = async () => - webpackMerge(baseConfig, { - entry: { index: ENTRY_INDEX }, - output: { - path: OUTPUT_PATH, - filename: 'opentrons-shared-data.js', - library: '@opentrons/shared-data', - libraryTarget: 'umd', - globalObject: 'this', - }, - }) diff --git a/step-generation/src/__tests__/consolidate.test.ts b/step-generation/src/__tests__/consolidate.test.ts index 11b20e65267..9733fe5caa6 100644 --- a/step-generation/src/__tests__/consolidate.test.ts +++ b/step-generation/src/__tests__/consolidate.test.ts @@ -1,4 +1,5 @@ import { beforeEach, describe, it, expect } from 'vitest' +import { getLabwareDefURI, fixtureTiprack300ul } from '@opentrons/shared-data' import { consolidate } from '../commandCreators/compound/consolidate' import { FIXED_TRASH_ID } from '../constants' import { @@ -25,7 +26,11 @@ import { blowoutInPlaceHelper, } from '../fixtures' import { DEST_WELL_BLOWOUT_DESTINATION } from '../utils' -import type { AspDispAirgapParams, CreateCommand } from '@opentrons/shared-data' +import type { + AspDispAirgapParams, + CreateCommand, + LabwareDefinition2, +} from '@opentrons/shared-data' import type { ConsolidateArgs, InvariantContext, RobotState } from '../types' const airGapHelper = makeAirGapHelper({ @@ -99,7 +104,7 @@ beforeEach(() => { mixInDestination: null, blowoutLocation: null, dropTipLocation: FIXED_TRASH_ID, - tipRack: 'tiprack1Id', + tipRack: getLabwareDefURI(fixtureTiprack300ul as LabwareDefinition2), aspirateXOffset: 0, dispenseXOffset: 0, aspirateYOffset: 0, @@ -3210,7 +3215,7 @@ describe('consolidate multi-channel', () => { const data: ConsolidateArgs = { ...args, volume: 140, - tipRack: 'tiprack1Id', + tipRack: getLabwareDefURI(fixtureTiprack300ul as LabwareDefinition2), changeTip: 'once', aspirateXOffset: 0, dispenseXOffset: 0, diff --git a/step-generation/src/__tests__/dispenseUpdateLiquidState.test.ts b/step-generation/src/__tests__/dispenseUpdateLiquidState.test.ts index 928a3eb281e..d24ed0a4c21 100644 --- a/step-generation/src/__tests__/dispenseUpdateLiquidState.test.ts +++ b/step-generation/src/__tests__/dispenseUpdateLiquidState.test.ts @@ -8,7 +8,12 @@ import merge from 'lodash/merge' import omit from 'lodash/omit' import produce from 'immer' import { createEmptyLiquidState, createTipLiquidState } from '../utils' -import { makeContext, DEFAULT_PIPETTE, SOURCE_LABWARE } from '../fixtures' +import { + makeContext, + DEFAULT_PIPETTE, + SOURCE_LABWARE, + getInitialRobotStateStandard, +} from '../fixtures' import { dispenseUpdateLiquidState, @@ -33,6 +38,10 @@ beforeEach(() => { useFullVolume: false, labwareId: SOURCE_LABWARE, wellName: 'A1', + robotStateAndWarnings: { + robotState: getInitialRobotStateStandard(invariantContext), + warnings: [], + }, } }) @@ -396,6 +405,10 @@ describe('...8-channel pipette', () => { useFullVolume: false, volume: 150, wellName: 'A1', + robotStateAndWarnings: { + robotState: getInitialRobotStateStandard(invariantContext), + warnings: [], + }, }, initialLiquidState ) diff --git a/step-generation/src/__tests__/distribute.test.ts b/step-generation/src/__tests__/distribute.test.ts index 6793b9df81e..a2bd499d1fc 100644 --- a/step-generation/src/__tests__/distribute.test.ts +++ b/step-generation/src/__tests__/distribute.test.ts @@ -1,5 +1,6 @@ import { beforeEach, describe, it, expect } from 'vitest' import { FIXED_TRASH_ID } from '../constants' +import { fixtureTiprack300ul, getLabwareDefURI } from '@opentrons/shared-data' import { ASPIRATE_OFFSET_FROM_BOTTOM_MM, blowoutHelper, @@ -24,7 +25,7 @@ import { blowoutInPlaceHelper, } from '../fixtures' import { distribute } from '../commandCreators/compound/distribute' -import type { CreateCommand } from '@opentrons/shared-data' +import type { CreateCommand, LabwareDefinition2 } from '@opentrons/shared-data' import type { DistributeArgs, InvariantContext, RobotState } from '../types' import { SOURCE_WELL_BLOWOUT_DESTINATION, @@ -73,7 +74,7 @@ beforeEach(() => { commandCreatorFnName: 'distribute', name: 'distribute test', description: 'test blah blah', - tipRack: 'tiprack1Id', + tipRack: getLabwareDefURI(fixtureTiprack300ul as LabwareDefinition2), pipette: DEFAULT_PIPETTE, sourceLabware: SOURCE_LABWARE, destLabware: DEST_LABWARE, @@ -254,7 +255,7 @@ describe('tip handling for multiple distribute chunks', () => { destWells: ['A2', 'A3', 'A4', 'A5'], changeTip: 'always', volume: 150, - tipRack: 'tiprack1Id', + tipRack: getLabwareDefURI(fixtureTiprack300ul as LabwareDefinition2), } as DistributeArgs const result = distribute( diff --git a/step-generation/src/__tests__/getIsSafePipetteMovement.test.ts b/step-generation/src/__tests__/getIsSafePipetteMovement.test.ts new file mode 100644 index 00000000000..b3ff5cba24d --- /dev/null +++ b/step-generation/src/__tests__/getIsSafePipetteMovement.test.ts @@ -0,0 +1,168 @@ +import { expect, describe, it } from 'vitest' +import { getIsSafePipetteMovement } from '../utils' +import { + LabwareDefinition2, + TEMPERATURE_MODULE_TYPE, + TEMPERATURE_MODULE_V2, + fixture96Plate, + fixtureP100096V2Specs, + fixtureTiprack1000ul, + fixtureTiprackAdapter, +} from '@opentrons/shared-data' +import { InvariantContext, RobotState } from '../types' + +const mockLabwareId = 'labwareId' +const mockPipId = 'pip' +const mockTiprackId = 'tiprackId' +const mockTipUri = 'mockTipUri' +const mockModule = 'moduleId' +const mockLabware2 = 'labwareId2' +const mockAdapter = 'adapterId' +const mockInvariantProperties: InvariantContext = { + pipetteEntities: { + pip: { + name: 'p1000_96', + id: 'pip', + tiprackDefURI: ['mockDefUri'], + tiprackLabwareDef: [fixtureTiprack1000ul as LabwareDefinition2], + spec: fixtureP100096V2Specs, + }, + }, + labwareEntities: { + [mockLabwareId]: { + id: mockLabwareId, + labwareDefURI: 'mockDefUri', + def: fixture96Plate as LabwareDefinition2, + }, + [mockTiprackId]: { + id: mockTiprackId, + labwareDefURI: mockTipUri, + def: fixtureTiprack1000ul as LabwareDefinition2, + }, + [mockAdapter]: { + id: mockAdapter, + labwareDefURI: 'mockAdapterUri', + def: fixtureTiprackAdapter as LabwareDefinition2, + }, + [mockLabware2]: { + id: mockLabware2, + labwareDefURI: 'mockDefUri', + def: fixture96Plate as LabwareDefinition2, + }, + }, + moduleEntities: {}, + additionalEquipmentEntities: {}, + config: { + OT_PD_DISABLE_MODULE_RESTRICTIONS: false, + }, +} + +const mockRobotState: RobotState = { + pipettes: { pip: { mount: 'left' } }, + labware: { [mockLabwareId]: { slot: 'D2' }, [mockTiprackId]: { slot: 'A2' } }, + modules: {}, + tipState: { tipracks: {}, pipettes: {} }, + liquidState: { pipettes: {}, labware: {}, additionalEquipment: {} }, +} +describe('getIsSafePipetteMovement', () => { + it('returns true when the labware id is a trash bin', () => { + const result = getIsSafePipetteMovement( + { + labware: {}, + pipettes: {}, + modules: {}, + tipState: {}, + liquidState: {}, + } as any, + { + labwareEntities: {}, + pipetteEntities: {}, + moduleEntities: {}, + additionalEquipmentEntities: { + trashBin: { name: 'trashBin', location: 'A3', id: 'trashBin' }, + }, + config: {} as any, + }, + 'mockId', + 'mockTrashBin', + mockTipUri, + { x: 0, y: 0, z: 0 } + ) + expect(result).toEqual(true) + }) + it('returns false when within pipette extents is false', () => { + const result = getIsSafePipetteMovement( + mockRobotState, + mockInvariantProperties, + mockPipId, + mockLabwareId, + mockTipUri, + { x: -12, y: -100, z: 20 } + ) + expect(result).toEqual(false) + }) + it('returns true when there are no collisions and a module near it', () => { + mockRobotState.modules = { + [mockModule]: { slot: 'D1', moduleState: {} as any }, + } + mockInvariantProperties.moduleEntities = { + [mockModule]: { + id: mockModule, + type: TEMPERATURE_MODULE_TYPE, + model: TEMPERATURE_MODULE_V2, + }, + } + const result = getIsSafePipetteMovement( + mockRobotState, + mockInvariantProperties, + mockPipId, + mockLabwareId, + mockTipUri, + { x: -1, y: 5, z: 20 } + ) + expect(result).toEqual(true) + }) + it('returns false when there is a tip that collides', () => { + mockRobotState.tipState.tipracks = { mockTiprackId: { A1: true } } + const result = getIsSafePipetteMovement( + mockRobotState, + mockInvariantProperties, + mockPipId, + mockLabwareId, + mockTipUri, + { x: -1, y: 5, z: 0 } + ) + expect(result).toEqual(false) + }) + it('returns false when there is a tall module nearby in a diagonal slot with adapter and labware', () => { + mockRobotState.modules = { + [mockModule]: { slot: 'C1', moduleState: {} as any }, + } + mockRobotState.labware = { + [mockLabwareId]: { slot: 'D2' }, + [mockAdapter]: { + slot: mockModule, + }, + [mockLabware2]: { + slot: mockAdapter, + }, + } + mockInvariantProperties.moduleEntities = { + [mockModule]: { + id: mockModule, + type: TEMPERATURE_MODULE_TYPE, + model: TEMPERATURE_MODULE_V2, + }, + } + const result = getIsSafePipetteMovement( + mockRobotState, + mockInvariantProperties, + mockPipId, + mockLabwareId, + mockTipUri, + { x: 0, y: 0, z: 0 } + ) + expect(result).toEqual(false) + }) + // todo(jr, 4/23/24): add more test cases, test thermocycler collision - i'll do this in a follow up +}) diff --git a/step-generation/src/__tests__/mix.test.ts b/step-generation/src/__tests__/mix.test.ts index 9fd099a5388..9f39d8722b7 100644 --- a/step-generation/src/__tests__/mix.test.ts +++ b/step-generation/src/__tests__/mix.test.ts @@ -1,6 +1,10 @@ import { beforeEach, describe, it, expect } from 'vitest' import flatMap from 'lodash/flatMap' -import { FIXED_TRASH_ID } from '@opentrons/shared-data' +import { + FIXED_TRASH_ID, + fixtureTiprack300ul, + getLabwareDefURI, +} from '@opentrons/shared-data' import { mix } from '../commandCreators/compound/mix' import { getRobotStateWithTipStandard, @@ -18,6 +22,7 @@ import { makeTouchTipHelper, delayCommand, } from '../fixtures' +import type { LabwareDefinition2 } from '@opentrons/shared-data' import type { ChangeTipOptions, InvariantContext, @@ -41,7 +46,7 @@ beforeEach(() => { commandCreatorFnName: 'mix', name: 'mix test', description: 'test blah blah', - tipRack: 'tiprack1Id', + tipRack: getLabwareDefURI(fixtureTiprack300ul as LabwareDefinition2), pipette: DEFAULT_PIPETTE, labware: SOURCE_LABWARE, diff --git a/step-generation/src/__tests__/ninetySixChannelCollision.test.ts b/step-generation/src/__tests__/ninetySixChannelCollision.test.ts deleted file mode 100644 index aae8c8acab9..00000000000 --- a/step-generation/src/__tests__/ninetySixChannelCollision.test.ts +++ /dev/null @@ -1,146 +0,0 @@ -import { beforeEach, describe, it, expect } from 'vitest' -import { getIsTallLabwareWestOf96Channel } from '../utils/ninetySixChannelCollision' -import type { LabwareDefinition2 } from '@opentrons/shared-data' -import type { RobotState, InvariantContext } from '../types' - -let invariantContext: InvariantContext -let robotState: RobotState - -const mockSourceId = 'sourceId' -const mockWestId = 'westId' -const mockPipetteId = 'pipetteId' -const mockTiprackId = 'tiprackId' -const mockSourceDef: LabwareDefinition2 = { - dimensions: { zDimension: 100 }, -} as any -const mockWestDef: LabwareDefinition2 = { - dimensions: { zDimension: 90 }, -} as any -const mockWestDefTall: LabwareDefinition2 = { - dimensions: { zDimension: 101 }, -} as any -const mockTiprackDefinition: LabwareDefinition2 = { - parameters: { tipLength: 10 }, -} as any -describe('getIsTallLabwareWestOf96Channel ', () => { - beforeEach(() => { - invariantContext = { - labwareEntities: { - [mockSourceId]: { - id: mockSourceId, - labwareDefURI: 'mockDefUri', - def: mockSourceDef, - }, - }, - additionalEquipmentEntities: {}, - moduleEntities: {}, - config: {} as any, - pipetteEntities: { - [mockPipetteId]: { - name: 'p1000_96', - id: mockPipetteId, - tiprackDefURI: ['mockUri'], - tiprackLabwareDef: [mockTiprackDefinition], - spec: {} as any, - }, - }, - } - robotState = { - labware: { [mockSourceId]: { slot: 'A1' } }, - pipettes: {}, - modules: {}, - tipState: { pipettes: { [mockPipetteId]: false } } as any, - liquidState: {} as any, - } - }) - it('should return false when the slot is in column is 1', () => { - expect( - getIsTallLabwareWestOf96Channel( - robotState, - invariantContext, - mockSourceId, - mockPipetteId, - mockTiprackId - ) - ).toBe(false) - }) - it('should return false when source id is a waste chute', () => { - invariantContext = { - ...invariantContext, - additionalEquipmentEntities: { - [mockSourceId]: { - id: mockSourceId, - name: 'wasteChute', - location: 'D3', - }, - }, - } - expect( - getIsTallLabwareWestOf96Channel( - robotState, - invariantContext, - mockSourceId, - mockPipetteId, - mockTiprackId - ) - ).toBe(false) - }) - it('should return false when there is no labware west of source labware', () => { - robotState.labware = { [mockSourceId]: { slot: 'A2' } } - expect( - getIsTallLabwareWestOf96Channel( - robotState, - invariantContext, - mockSourceId, - mockPipetteId, - mockTiprackId - ) - ).toBe(false) - }) - it('should return false when the west labware height is not tall enough', () => { - invariantContext.labwareEntities = { - ...invariantContext.labwareEntities, - [mockWestId]: { - id: mockWestId, - labwareDefURI: 'mockDefUri', - def: mockWestDef, - }, - } - robotState.labware = { - [mockSourceId]: { slot: 'A2' }, - [mockWestId]: { slot: 'A1' }, - } - expect( - getIsTallLabwareWestOf96Channel( - robotState, - invariantContext, - mockSourceId, - mockPipetteId, - mockTiprackId - ) - ).toBe(false) - }) - it('should return true when the west labware height is tall enough', () => { - invariantContext.labwareEntities = { - ...invariantContext.labwareEntities, - [mockWestId]: { - id: mockWestId, - labwareDefURI: 'mockDefUri', - def: mockWestDefTall, - }, - } - robotState.labware = { - [mockSourceId]: { slot: 'A2' }, - [mockWestId]: { slot: 'A1' }, - } - expect( - getIsTallLabwareWestOf96Channel( - robotState, - invariantContext, - mockSourceId, - mockPipetteId, - mockTiprackId - ) - ).toBe(true) - }) -}) diff --git a/step-generation/src/__tests__/replaceTip.test.ts b/step-generation/src/__tests__/replaceTip.test.ts index 0cd85058ca4..01a88101f6b 100644 --- a/step-generation/src/__tests__/replaceTip.test.ts +++ b/step-generation/src/__tests__/replaceTip.test.ts @@ -1,6 +1,11 @@ import { beforeEach, describe, it, expect } from 'vitest' import merge from 'lodash/merge' -import { COLUMN } from '@opentrons/shared-data' +import { + COLUMN, + fixtureTiprack1000ul, + fixtureTiprack300ul, + getLabwareDefURI, +} from '@opentrons/shared-data' import { getInitialRobotStateStandard, makeContext, @@ -13,14 +18,17 @@ import { moveToAddressableAreaHelper, DEFAULT_PIPETTE, } from '../fixtures' -import { FIXED_TRASH_ID } from '..' import { replaceTip } from '../commandCreators/atomic/replaceTip' +import { FIXED_TRASH_ID } from '../constants' +import type { LabwareDefinition2 } from '@opentrons/shared-data' import type { InvariantContext, RobotState } from '../types' const tiprack1Id = 'tiprack1Id' const tiprack2Id = 'tiprack2Id' const tiprack4Id = 'tiprack4Id' const tiprack5Id = 'tiprack5Id' +const tiprackURI1 = getLabwareDefURI(fixtureTiprack300ul as LabwareDefinition2) +const tiprackURI2 = getLabwareDefURI(fixtureTiprack1000ul as LabwareDefinition2) const p300SingleId = DEFAULT_PIPETTE const p300MultiId = 'p300MultiId' const p100096Id = 'p100096Id' @@ -38,7 +46,7 @@ describe('replaceTip', () => { { pipette: p300SingleId, dropTipLocation: FIXED_TRASH_ID, - tipRack: tiprack1Id, + tipRack: tiprackURI1, }, invariantContext, initialRobotState @@ -51,7 +59,7 @@ describe('replaceTip', () => { { pipette: p300SingleId, dropTipLocation: FIXED_TRASH_ID, - tipRack: tiprack1Id, + tipRack: tiprackURI1, }, invariantContext, merge({}, initialRobotState, { @@ -85,7 +93,7 @@ describe('replaceTip', () => { { pipette: p300SingleId, dropTipLocation: FIXED_TRASH_ID, - tipRack: tiprack1Id, + tipRack: tiprackURI1, }, invariantContext, initialTestRobotState @@ -110,7 +118,7 @@ describe('replaceTip', () => { { pipette: p300SingleId, dropTipLocation: FIXED_TRASH_ID, - tipRack: tiprack1Id, + tipRack: tiprackURI1, }, invariantContext, initialTestRobotState @@ -136,7 +144,7 @@ describe('replaceTip', () => { { pipette: p300SingleId, dropTipLocation: FIXED_TRASH_ID, - tipRack: tiprack1Id, + tipRack: tiprackURI1, }, invariantContext, initialTestRobotState @@ -175,7 +183,7 @@ describe('replaceTip', () => { { pipette: p300SingleId, dropTipLocation: 'wasteChuteId', - tipRack: tiprack1Id, + tipRack: tiprackURI1, }, invariantContext, initialTestRobotState @@ -194,7 +202,7 @@ describe('replaceTip', () => { { pipette: p300MultiId, dropTipLocation: FIXED_TRASH_ID, - tipRack: tiprack1Id, + tipRack: tiprackURI1, }, invariantContext, initialRobotState @@ -221,7 +229,7 @@ describe('replaceTip', () => { { pipette: p300MultiId, dropTipLocation: FIXED_TRASH_ID, - tipRack: tiprack1Id, + tipRack: tiprackURI1, }, invariantContext, robotStateWithTipA1Missing @@ -247,7 +255,7 @@ describe('replaceTip', () => { { pipette: p300MultiId, dropTipLocation: FIXED_TRASH_ID, - tipRack: tiprack1Id, + tipRack: tiprackURI1, }, invariantContext, robotStateWithTipsOnMulti @@ -292,7 +300,7 @@ describe('replaceTip', () => { { pipette: p100096Id, dropTipLocation: 'wasteChuteId', - tipRack: tiprack5Id, + tipRack: tiprackURI2, nozzles: COLUMN, }, invariantContext, diff --git a/step-generation/src/__tests__/robotStateSelectors.test.ts b/step-generation/src/__tests__/robotStateSelectors.test.ts index e74549a87ed..637ddaa22da 100644 --- a/step-generation/src/__tests__/robotStateSelectors.test.ts +++ b/step-generation/src/__tests__/robotStateSelectors.test.ts @@ -22,7 +22,9 @@ import { InvariantContext } from '../types' let invariantContext: InvariantContext const fixtureTiprack300ul = _fixtureTiprack300ul as LabwareDefinition2 -const mockTiprackId = 'tiprack1Id' +const mockTiprackURI = getLabwareDefURI( + fixtureTiprack300ul as LabwareDefinition2 +) beforeEach(() => { invariantContext = makeContext() @@ -153,7 +155,7 @@ describe('getNextTiprack - single-channel', () => { const result = getNextTiprack( DEFAULT_PIPETTE, - mockTiprackId, + mockTiprackURI, invariantContext, robotState ) @@ -172,7 +174,7 @@ describe('getNextTiprack - single-channel', () => { const result = getNextTiprack( DEFAULT_PIPETTE, - mockTiprackId, + mockTiprackURI, invariantContext, robotState ) @@ -191,7 +193,7 @@ describe('getNextTiprack - single-channel', () => { }) const result = getNextTiprack( DEFAULT_PIPETTE, - mockTiprackId, + mockTiprackURI, invariantContext, robotState ) @@ -215,7 +217,7 @@ describe('getNextTiprack - single-channel', () => { robotState.tipState.tipracks.tiprack2Id.A1 = false const result = getNextTiprack( DEFAULT_PIPETTE, - mockTiprackId, + mockTiprackURI, invariantContext, robotState ) @@ -236,7 +238,7 @@ describe('getNextTiprack - single-channel', () => { }) const result = getNextTiprack( DEFAULT_PIPETTE, - mockTiprackId, + mockTiprackURI, invariantContext, robotState ) @@ -258,7 +260,7 @@ describe('getNextTiprack - 8-channel', () => { const result = getNextTiprack( 'p300MultiId', - mockTiprackId, + mockTiprackURI, invariantContext, robotState ) @@ -284,7 +286,7 @@ describe('getNextTiprack - 8-channel', () => { } const result = getNextTiprack( 'p300MultiId', - mockTiprackId, + mockTiprackURI, invariantContext, robotState ) @@ -304,7 +306,7 @@ describe('getNextTiprack - 8-channel', () => { }) const result = getNextTiprack( 'p300MultiId', - mockTiprackId, + mockTiprackURI, invariantContext, robotState ) @@ -339,7 +341,7 @@ describe('getNextTiprack - 8-channel', () => { const result = getNextTiprack( 'p300MultiId', - mockTiprackId, + mockTiprackURI, invariantContext, robotState ) @@ -360,7 +362,7 @@ describe('getNextTiprack - 8-channel', () => { }) const result = getNextTiprack( 'p300MultiId', - mockTiprackId, + mockTiprackURI, invariantContext, robotState ) @@ -420,7 +422,7 @@ describe('getNextTiprack - 8-channel', () => { const result = getNextTiprack( 'p300MultiId', - mockTiprackId, + mockTiprackURI, invariantContext, robotState ) @@ -446,7 +448,7 @@ describe('getNextTiprack - 8-channel', () => { }) const result = getNextTiprack( 'p300MultiId', - mockTiprackId, + mockTiprackURI, invariantContext, robotState ) diff --git a/step-generation/src/__tests__/transfer.test.ts b/step-generation/src/__tests__/transfer.test.ts index b3da39db41d..72c89fc264a 100644 --- a/step-generation/src/__tests__/transfer.test.ts +++ b/step-generation/src/__tests__/transfer.test.ts @@ -1,6 +1,8 @@ import { beforeEach, describe, it, expect, test } from 'vitest' import { ONE_CHANNEL_WASTE_CHUTE_ADDRESSABLE_AREA, + fixtureTiprack300ul, + getLabwareDefURI, WASTE_CHUTE_CUTOUT, } from '@opentrons/shared-data' import { @@ -31,6 +33,7 @@ import { SOURCE_WELL_BLOWOUT_DESTINATION, } from '../utils/misc' import { transfer } from '../commandCreators/compound/transfer' +import type { LabwareDefinition2 } from '@opentrons/shared-data' import type { InvariantContext, RobotState, TransferArgs } from '../types' const airGapHelper = makeAirGapHelper({ @@ -68,7 +71,7 @@ beforeEach(() => { name: 'Transfer Test', description: 'test blah blah', pipette: DEFAULT_PIPETTE, - tipRack: 'tiprack1Id', + tipRack: getLabwareDefURI(fixtureTiprack300ul as LabwareDefinition2), sourceLabware: SOURCE_LABWARE, destLabware: DEST_LABWARE, diff --git a/step-generation/src/commandCreators/atomic/aspirate.ts b/step-generation/src/commandCreators/atomic/aspirate.ts index d7226da3387..c429f7ed24c 100644 --- a/step-generation/src/commandCreators/atomic/aspirate.ts +++ b/step-generation/src/commandCreators/atomic/aspirate.ts @@ -41,6 +41,7 @@ export const aspirate: CommandCreator = ( yOffset, } = args const actionName = 'aspirate' + const labwareState = prevRobotState.labware const errors: CommandCreatorError[] = [] const pipetteSpec = invariantContext.pipetteEntities[pipette]?.spec const isFlexPipette = @@ -75,6 +76,13 @@ export const aspirate: CommandCreator = ( if (COLUMN_4_SLOTS.includes(slotName)) { errors.push(errorCreators.pipettingIntoColumn4({ typeOfStep: actionName })) + } else if (labwareState[slotName] != null) { + const adapterSlot = labwareState[slotName].slot + if (COLUMN_4_SLOTS.includes(adapterSlot)) { + errors.push( + errorCreators.pipettingIntoColumn4({ typeOfStep: actionName }) + ) + } } if ( diff --git a/step-generation/src/commandCreators/atomic/blowout.ts b/step-generation/src/commandCreators/atomic/blowout.ts index ff3be46d786..b56c57fc9db 100644 --- a/step-generation/src/commandCreators/atomic/blowout.ts +++ b/step-generation/src/commandCreators/atomic/blowout.ts @@ -15,6 +15,7 @@ export const blowout: CommandCreator = ( const actionName = 'blowout' const errors: CommandCreatorError[] = [] const pipetteData = prevRobotState.pipettes[pipetteId] + const labwareState = prevRobotState.labware const slotName = getLabwareSlot( labwareId, prevRobotState.labware, @@ -56,6 +57,13 @@ export const blowout: CommandCreator = ( if (COLUMN_4_SLOTS.includes(slotName)) { errors.push(errorCreators.pipettingIntoColumn4({ typeOfStep: actionName })) + } else if (labwareState[slotName] != null) { + const adapterSlot = labwareState[slotName].slot + if (COLUMN_4_SLOTS.includes(adapterSlot)) { + errors.push( + errorCreators.pipettingIntoColumn4({ typeOfStep: actionName }) + ) + } } if (errors.length > 0) { diff --git a/step-generation/src/commandCreators/atomic/dispense.ts b/step-generation/src/commandCreators/atomic/dispense.ts index 2bec571bd6e..8523eab1f84 100644 --- a/step-generation/src/commandCreators/atomic/dispense.ts +++ b/step-generation/src/commandCreators/atomic/dispense.ts @@ -38,6 +38,7 @@ export const dispense: CommandCreator = ( yOffset, } = args const actionName = 'dispense' + const labwareState = prevRobotState.labware const errors: CommandCreatorError[] = [] const pipetteSpec = invariantContext.pipetteEntities[pipette]?.spec const isFlexPipette = @@ -93,6 +94,13 @@ export const dispense: CommandCreator = ( if (COLUMN_4_SLOTS.includes(slotName)) { errors.push(errorCreators.pipettingIntoColumn4({ typeOfStep: actionName })) + } else if (labwareState[slotName] != null) { + const adapterSlot = labwareState[slotName].slot + if (COLUMN_4_SLOTS.includes(adapterSlot)) { + errors.push( + errorCreators.pipettingIntoColumn4({ typeOfStep: actionName }) + ) + } } if ( diff --git a/step-generation/src/commandCreators/atomic/moveToWell.ts b/step-generation/src/commandCreators/atomic/moveToWell.ts index e16f1cff417..920d86daffc 100644 --- a/step-generation/src/commandCreators/atomic/moveToWell.ts +++ b/step-generation/src/commandCreators/atomic/moveToWell.ts @@ -26,6 +26,7 @@ export const moveToWell: CommandCreator = ( const { pipette, labware, well, offset, minimumZHeight, forceDirect } = args const actionName = 'moveToWell' const errors: CommandCreatorError[] = [] + const labwareState = prevRobotState.labware // TODO(2020-07-30, IL): the below is duplicated or at least similar // across aspirate/dispense/blowout, we can probably DRY it up const pipetteSpec = invariantContext.pipetteEntities[pipette]?.spec @@ -63,6 +64,13 @@ export const moveToWell: CommandCreator = ( errors.push( errorCreators.pipettingIntoColumn4({ typeOfStep: 'move to well' }) ) + } else if (labwareState[slotName] != null) { + const adapterSlot = labwareState[slotName].slot + if (COLUMN_4_SLOTS.includes(adapterSlot)) { + errors.push( + errorCreators.pipettingIntoColumn4({ typeOfStep: actionName }) + ) + } } if ( diff --git a/step-generation/src/commandCreators/atomic/replaceTip.ts b/step-generation/src/commandCreators/atomic/replaceTip.ts index 85160be713c..856b89c9e30 100644 --- a/step-generation/src/commandCreators/atomic/replaceTip.ts +++ b/step-generation/src/commandCreators/atomic/replaceTip.ts @@ -7,7 +7,7 @@ import { curryCommandCreator, getIsHeaterShakerEastWestMultiChannelPipette, getIsHeaterShakerEastWestWithLatchOpen, - getIsTallLabwareWestOf96Channel, + getIsSafePipetteMovement, getLabwareSlot, modulePipetteCollision, pipetteAdjacentHeaterShakerWhileShaking, @@ -39,6 +39,13 @@ const _pickUpTip: CommandCreator = ( errors.push( errorCreators.pipettingIntoColumn4({ typeOfStep: 'pick up tip' }) ) + } else if (prevRobotState.labware[tiprackSlot] != null) { + const adapterSlot = prevRobotState.labware[tiprackSlot].slot + if (COLUMN_4_SLOTS.includes(adapterSlot)) { + errors.push( + errorCreators.pipettingIntoColumn4({ typeOfStep: 'pick up tip' }) + ) + } } if (errors.length > 0) { @@ -160,23 +167,18 @@ export const replaceTip: CommandCreator = ( if ( channels === 96 && nozzles === COLUMN && - getIsTallLabwareWestOf96Channel( + !getIsSafePipetteMovement( prevRobotState, invariantContext, nextTiprack.tiprackId, pipette, - tipRack + tipRack, + // we don't adjust the offset when moving to the tiprack + { x: 0, y: 0 } ) ) { return { - errors: [ - errorCreators.tallLabwareWestOf96ChannelPipetteLabware({ - source: 'tiprack', - labware: - invariantContext.labwareEntities[nextTiprack.tiprackId].def.metadata - .displayName, - }), - ], + errors: [errorCreators.possiblePipetteCollision()], } } diff --git a/step-generation/src/commandCreators/compound/consolidate.ts b/step-generation/src/commandCreators/compound/consolidate.ts index b37f2ede1b0..f7fc4c85f9d 100644 --- a/step-generation/src/commandCreators/compound/consolidate.ts +++ b/step-generation/src/commandCreators/compound/consolidate.ts @@ -18,7 +18,7 @@ import { airGapHelper, dispenseLocationHelper, moveHelper, - getIsTallLabwareWestOf96Channel, + getIsSafePipetteMovement, getWasteChuteAddressableAreaNamePip, } from '../../utils' import { @@ -56,6 +56,31 @@ export const consolidate: CommandCreator = ( * 'once': get a new tip at the beginning of the consolidate step, and use it throughout * 'never': reuse the tip from the last step */ + + // TODO: BC 2019-07-08 these argument names are a bit misleading, instead of being values bound + // to the action of aspiration of dispensing in a given command, they are actually values bound + // to a given labware associated with a command (e.g. Source, Destination). For this reason we + // currently remapping the inner mix values. Those calls to mixUtil should become easier to read + // when we decide to rename these fields/args... probably all the way up to the UI level. + const { + aspirateDelay, + aspirateFlowRateUlSec, + aspirateOffsetFromBottomMm, + blowoutFlowRateUlSec, + blowoutOffsetFromTopMm, + dispenseAirGapVolume, + dispenseDelay, + dispenseFlowRateUlSec, + dispenseOffsetFromBottomMm, + mixFirstAspirate, + mixInDestination, + dropTipLocation, + aspirateXOffset, + aspirateYOffset, + dispenseXOffset, + dispenseYOffset, + } = args + const actionName = 'consolidate' const pipetteData = prevRobotState.pipettes[args.pipette] const is96Channel = @@ -91,72 +116,37 @@ export const consolidate: CommandCreator = ( if ( is96Channel && args.nozzles === COLUMN && - getIsTallLabwareWestOf96Channel( + !getIsSafePipetteMovement( prevRobotState, invariantContext, - args.sourceLabware, args.pipette, - args.tipRack + args.sourceLabware, + args.tipRack, + { x: aspirateXOffset, y: aspirateYOffset } ) ) { return { - errors: [ - errorCreators.tallLabwareWestOf96ChannelPipetteLabware({ - source: 'aspirate', - labware: - invariantContext.labwareEntities[args.sourceLabware].def.metadata - .displayName, - }), - ], + errors: [errorCreators.possiblePipetteCollision()], } } if ( is96Channel && args.nozzles === COLUMN && - getIsTallLabwareWestOf96Channel( + !getIsSafePipetteMovement( prevRobotState, invariantContext, - args.destLabware, args.pipette, - args.tipRack + args.destLabware, + args.tipRack, + { x: dispenseXOffset, y: dispenseYOffset } ) ) { return { - errors: [ - errorCreators.tallLabwareWestOf96ChannelPipetteLabware({ - source: 'dispense', - labware: - invariantContext.labwareEntities[args.destLabware].def.metadata - .displayName, - }), - ], + errors: [errorCreators.possiblePipetteCollision()], } } - // TODO: BC 2019-07-08 these argument names are a bit misleading, instead of being values bound - // to the action of aspiration of dispensing in a given command, they are actually values bound - // to a given labware associated with a command (e.g. Source, Destination). For this reason we - // currently remapping the inner mix values. Those calls to mixUtil should become easier to read - // when we decide to rename these fields/args... probably all the way up to the UI level. - const { - aspirateDelay, - aspirateFlowRateUlSec, - aspirateOffsetFromBottomMm, - blowoutFlowRateUlSec, - blowoutOffsetFromTopMm, - dispenseAirGapVolume, - dispenseDelay, - dispenseFlowRateUlSec, - dispenseOffsetFromBottomMm, - mixFirstAspirate, - mixInDestination, - dropTipLocation, - aspirateXOffset, - aspirateYOffset, - dispenseXOffset, - dispenseYOffset, - } = args const aspirateAirGapVolume = args.aspirateAirGapVolume || 0 const maxWellsPerChunk = Math.floor( getPipetteWithTipMaxVol(args.pipette, invariantContext, args.tipRack) / diff --git a/step-generation/src/commandCreators/compound/distribute.ts b/step-generation/src/commandCreators/compound/distribute.ts index 520ce06aeb4..eae11c1452f 100644 --- a/step-generation/src/commandCreators/compound/distribute.ts +++ b/step-generation/src/commandCreators/compound/distribute.ts @@ -16,7 +16,7 @@ import { blowoutUtil, wasteChuteCommandsUtil, getDispenseAirGapLocation, - getIsTallLabwareWestOf96Channel, + getIsSafePipetteMovement, getWasteChuteAddressableAreaNamePip, } from '../../utils' import { @@ -53,6 +53,26 @@ export const distribute: CommandCreator = ( * 'once': get a new tip at the beginning of the distribute step, and use it throughout * 'never': reuse the tip from the last step */ + + // TODO: BC 2019-07-08 these argument names are a bit misleading, instead of being values bound + // to the action of aspiration of dispensing in a given command, they are actually values bound + // to a given labware associated with a command (e.g. Source, Destination). For this reason we + // currently remapping the inner mix values. Those calls to mixUtil should become easier to read + // when we decide to rename these fields/args... probably all the way up to the UI level. + const { + aspirateDelay, + aspirateFlowRateUlSec, + aspirateOffsetFromBottomMm, + dispenseDelay, + dispenseFlowRateUlSec, + dispenseOffsetFromBottomMm, + blowoutLocation, + aspirateXOffset, + aspirateYOffset, + dispenseXOffset, + dispenseYOffset, + } = args + // TODO Ian 2018-05-03 next ~20 lines match consolidate.js const actionName = 'distribute' const errors: CommandCreatorError[] = [] @@ -91,67 +111,38 @@ export const distribute: CommandCreator = ( if ( is96Channel && args.nozzles === COLUMN && - getIsTallLabwareWestOf96Channel( + !getIsSafePipetteMovement( prevRobotState, invariantContext, - args.sourceLabware, args.pipette, - args.tipRack + args.sourceLabware, + args.tipRack, + { x: aspirateXOffset, y: aspirateYOffset } ) ) { - errors.push( - errorCreators.tallLabwareWestOf96ChannelPipetteLabware({ - source: 'aspirate', - labware: - invariantContext.labwareEntities[args.sourceLabware].def.metadata - .displayName, - }) - ) + errors.push(errorCreators.possiblePipetteCollision()) } if ( is96Channel && args.nozzles === COLUMN && - getIsTallLabwareWestOf96Channel( + !getIsSafePipetteMovement( prevRobotState, invariantContext, - args.destLabware, args.pipette, - args.tipRack + args.destLabware, + args.tipRack, + { x: dispenseXOffset, y: dispenseYOffset } ) ) { - errors.push( - errorCreators.tallLabwareWestOf96ChannelPipetteLabware({ - source: 'dispense', - labware: - invariantContext.labwareEntities[args.destLabware].def.metadata - .displayName, - }) - ) + errors.push(errorCreators.possiblePipetteCollision()) } if (errors.length > 0) return { errors, } - // TODO: BC 2019-07-08 these argument names are a bit misleading, instead of being values bound - // to the action of aspiration of dispensing in a given command, they are actually values bound - // to a given labware associated with a command (e.g. Source, Destination). For this reason we - // currently remapping the inner mix values. Those calls to mixUtil should become easier to read - // when we decide to rename these fields/args... probably all the way up to the UI level. - const { - aspirateDelay, - aspirateFlowRateUlSec, - aspirateOffsetFromBottomMm, - dispenseDelay, - dispenseFlowRateUlSec, - dispenseOffsetFromBottomMm, - blowoutLocation, - aspirateXOffset, - aspirateYOffset, - dispenseXOffset, - dispenseYOffset, - } = args + const aspirateAirGapVolume = args.aspirateAirGapVolume || 0 const dispenseAirGapVolume = args.dispenseAirGapVolume || 0 // TODO error on negative args.disposalVolume? diff --git a/step-generation/src/commandCreators/compound/mix.ts b/step-generation/src/commandCreators/compound/mix.ts index 284529c7c1f..317613c1524 100644 --- a/step-generation/src/commandCreators/compound/mix.ts +++ b/step-generation/src/commandCreators/compound/mix.ts @@ -5,7 +5,7 @@ import { blowoutUtil, curryCommandCreator, reduceCommandCreators, - getIsTallLabwareWestOf96Channel, + getIsSafePipetteMovement, } from '../../utils' import * as errorCreators from '../../errorCreators' import { @@ -178,25 +178,27 @@ export const mix: CommandCreator = ( return { errors: [errorCreators.dropTipLocationDoesNotExist()] } } - if ( - is96Channel && - data.nozzles === COLUMN && - getIsTallLabwareWestOf96Channel( + if (is96Channel && data.nozzles === COLUMN) { + const isAspirateSafePipetteMovement = getIsSafePipetteMovement( prevRobotState, invariantContext, + pipette, labware, + tipRack, + { x: aspirateXOffset, y: aspirateYOffset } + ) + const isDispenseSafePipetteMovement = getIsSafePipetteMovement( + prevRobotState, + invariantContext, pipette, - tipRack + labware, + tipRack, + { x: dispenseXOffset, y: dispenseYOffset } ) - ) { - return { - errors: [ - errorCreators.tallLabwareWestOf96ChannelPipetteLabware({ - source: 'mix', - labware: - invariantContext.labwareEntities[labware].def.metadata.displayName, - }), - ], + if (!isAspirateSafePipetteMovement && !isDispenseSafePipetteMovement) { + return { + errors: [errorCreators.possiblePipetteCollision()], + } } } const stateNozzles = prevRobotState.pipettes[pipette].nozzles diff --git a/step-generation/src/commandCreators/compound/transfer.ts b/step-generation/src/commandCreators/compound/transfer.ts index 2d16c8064bf..9c59d301aa4 100644 --- a/step-generation/src/commandCreators/compound/transfer.ts +++ b/step-generation/src/commandCreators/compound/transfer.ts @@ -18,7 +18,7 @@ import { getTrashOrLabware, dispenseLocationHelper, moveHelper, - getIsTallLabwareWestOf96Channel, + getIsSafePipetteMovement, getWasteChuteAddressableAreaNamePip, } from '../../utils' import { @@ -63,6 +63,27 @@ export const transfer: CommandCreator = ( NOTE: In some situations, different changeTip options have equivalent outcomes. That's OK. */ + // TODO: BC 2019-07-08 these argument names are a bit misleading, instead of being values bound + // to the action of aspiration of dispensing in a given command, they are actually values bound + // to a given labware associated with a command (e.g. Source, Destination). For this reason we + // currently remapping the inner mix values. Those calls to mixUtil should become easier to read + // when we decide to rename these fields/args... probably all the way up to the UI level. + const { + aspirateDelay, + dispenseDelay, + aspirateFlowRateUlSec, + aspirateOffsetFromBottomMm, + blowoutFlowRateUlSec, + blowoutOffsetFromTopMm, + dispenseFlowRateUlSec, + dispenseOffsetFromBottomMm, + tipRack, + aspirateXOffset, + aspirateYOffset, + dispenseXOffset, + dispenseYOffset, + } = args + const trashOrLabware = getTrashOrLabware( invariantContext.labwareEntities, invariantContext.additionalEquipmentEntities, @@ -130,43 +151,31 @@ export const transfer: CommandCreator = ( if ( is96Channel && args.nozzles === COLUMN && - getIsTallLabwareWestOf96Channel( + !getIsSafePipetteMovement( prevRobotState, invariantContext, - args.sourceLabware, args.pipette, - args.tipRack + args.sourceLabware, + args.tipRack, + { x: aspirateXOffset, y: aspirateYOffset, z: aspirateOffsetFromBottomMm } ) ) { - errors.push( - errorCreators.tallLabwareWestOf96ChannelPipetteLabware({ - source: 'aspirate', - labware: - invariantContext.labwareEntities[args.sourceLabware].def.metadata - .displayName, - }) - ) + errors.push(errorCreators.possiblePipetteCollision()) } if ( is96Channel && args.nozzles === COLUMN && - getIsTallLabwareWestOf96Channel( + !getIsSafePipetteMovement( prevRobotState, invariantContext, - args.destLabware, args.pipette, - args.tipRack + args.destLabware, + args.tipRack, + { x: dispenseXOffset, y: dispenseYOffset, z: dispenseOffsetFromBottomMm } ) ) { - errors.push( - errorCreators.tallLabwareWestOf96ChannelPipetteLabware({ - source: 'dispense', - labware: - invariantContext.labwareEntities[args.destLabware].def.metadata - .displayName, - }) - ) + errors.push(errorCreators.possiblePipetteCollision()) } if (errors.length > 0) @@ -190,26 +199,6 @@ export const transfer: CommandCreator = ( pipetteSpec.channels ) - // TODO: BC 2019-07-08 these argument names are a bit misleading, instead of being values bound - // to the action of aspiration of dispensing in a given command, they are actually values bound - // to a given labware associated with a command (e.g. Source, Destination). For this reason we - // currently remapping the inner mix values. Those calls to mixUtil should become easier to read - // when we decide to rename these fields/args... probably all the way up to the UI level. - const { - aspirateDelay, - dispenseDelay, - aspirateFlowRateUlSec, - aspirateOffsetFromBottomMm, - blowoutFlowRateUlSec, - blowoutOffsetFromTopMm, - dispenseFlowRateUlSec, - dispenseOffsetFromBottomMm, - tipRack, - aspirateXOffset, - aspirateYOffset, - dispenseXOffset, - dispenseYOffset, - } = args const aspirateAirGapVolume = args.aspirateAirGapVolume || 0 const dispenseAirGapVolume = args.dispenseAirGapVolume || 0 const effectiveTransferVol = diff --git a/step-generation/src/errorCreators.ts b/step-generation/src/errorCreators.ts index 50a271effe0..581b04d72f9 100644 --- a/step-generation/src/errorCreators.ts +++ b/step-generation/src/errorCreators.ts @@ -175,13 +175,11 @@ export const tallLabwareEastWestOfHeaterShaker = ( } } -export const tallLabwareWestOf96ChannelPipetteLabware = (args: { - source: string - labware: string -}): CommandCreatorError => { +export const possiblePipetteCollision = (): CommandCreatorError => { return { - type: 'TALL_LABWARE_WEST_OF_96_CHANNEL_LABWARE', - message: `Labware to the left of the ${args.source} ${args.labware} is too tall and will collide with the 96-channel.`, + type: 'POSSIBLE_PIPETTE_COLLISION', + message: + 'There is a possibility that the Pipette will collide with the a labware or module on the deck', } } diff --git a/step-generation/src/getNextRobotStateAndWarnings/dispenseUpdateLiquidState.ts b/step-generation/src/getNextRobotStateAndWarnings/dispenseUpdateLiquidState.ts index cf27f155d05..84d26e219c1 100644 --- a/step-generation/src/getNextRobotStateAndWarnings/dispenseUpdateLiquidState.ts +++ b/step-generation/src/getNextRobotStateAndWarnings/dispenseUpdateLiquidState.ts @@ -1,6 +1,6 @@ -import assert from 'assert' import mapValues from 'lodash/mapValues' import reduce from 'lodash/reduce' +import { COLUMN } from '@opentrons/shared-data' import { splitLiquid, mergeLiquid, @@ -12,7 +12,9 @@ import type { InvariantContext, LocationLiquidState, SourceAndDest, + RobotStateAndWarnings, } from '../types' + type LiquidState = RobotState['liquidState'] export interface DispenseUpdateLiquidStateArgs { invariantContext: InvariantContext @@ -20,6 +22,7 @@ export interface DispenseUpdateLiquidStateArgs { pipetteId: string // volume value is required when useFullVolume is false useFullVolume: boolean + robotStateAndWarnings: RobotStateAndWarnings wellName?: string labwareId?: string volume?: number @@ -30,6 +33,7 @@ export function dispenseUpdateLiquidState( args: DispenseUpdateLiquidStateArgs ): void { const { + robotStateAndWarnings, invariantContext, labwareId, pipetteId, @@ -39,6 +43,8 @@ export function dispenseUpdateLiquidState( wellName, } = args const pipetteSpec = invariantContext.pipetteEntities[pipetteId].spec + const nozzles = robotStateAndWarnings.robotState.pipettes[pipetteId].nozzles + const channels = nozzles === COLUMN ? 8 : pipetteSpec.channels const trashId = Object.values( invariantContext.additionalEquipmentEntities ).find(aE => aE.name === 'wasteChute' || aE.name === 'trashBin')?.id @@ -59,17 +65,17 @@ export function dispenseUpdateLiquidState( const labwareDef = labwareId != null ? invariantContext.labwareEntities[labwareId].def : null - assert( + console.assert( !(useFullVolume && typeof volume === 'number'), 'dispenseUpdateLiquidState takes either `volume` or `useFullVolume`, but got both' ) - assert( + console.assert( typeof volume === 'number' || useFullVolume, 'in dispenseUpdateLiquidState, either volume or useFullVolume are required' ) const { wellsForTips, allWellsShared } = labwareDef != null && wellName != null - ? getWellsForTips(pipetteSpec.channels, labwareDef, wellName) + ? getWellsForTips(channels, labwareDef, wellName) : { wellsForTips: null, allWellsShared: true } const liquidLabware = diff --git a/step-generation/src/getNextRobotStateAndWarnings/forAspirate.ts b/step-generation/src/getNextRobotStateAndWarnings/forAspirate.ts index 62cd0348ded..e8572dd77fc 100644 --- a/step-generation/src/getNextRobotStateAndWarnings/forAspirate.ts +++ b/step-generation/src/getNextRobotStateAndWarnings/forAspirate.ts @@ -1,4 +1,3 @@ -import assert from 'assert' import range from 'lodash/range' import isEmpty from 'lodash/isEmpty' import uniq from 'lodash/uniq' @@ -32,7 +31,7 @@ export function forAspirate( params.wellName ) - assert( + console.assert( // @ts-expect-error (sa, 2021-05-03): this assert is unnecessary uniq(wellsForTips).length === allWellsShared ? 1 : wellsForTips.length, `expected all wells to be shared, or no wells to be shared. Got: ${JSON.stringify( diff --git a/step-generation/src/getNextRobotStateAndWarnings/forBlowout.ts b/step-generation/src/getNextRobotStateAndWarnings/forBlowout.ts index 2bcffe0bc23..13a2470854e 100644 --- a/step-generation/src/getNextRobotStateAndWarnings/forBlowout.ts +++ b/step-generation/src/getNextRobotStateAndWarnings/forBlowout.ts @@ -15,5 +15,6 @@ export function forBlowout( wellName, prevLiquidState: robotState.liquidState, invariantContext, + robotStateAndWarnings, }) } diff --git a/step-generation/src/getNextRobotStateAndWarnings/forDispense.ts b/step-generation/src/getNextRobotStateAndWarnings/forDispense.ts index 8b08591ea84..6ffaa3da814 100644 --- a/step-generation/src/getNextRobotStateAndWarnings/forDispense.ts +++ b/step-generation/src/getNextRobotStateAndWarnings/forDispense.ts @@ -16,5 +16,6 @@ export function forDispense( useFullVolume: false, volume, wellName, + robotStateAndWarnings, }) } diff --git a/step-generation/src/getNextRobotStateAndWarnings/forDropTip.ts b/step-generation/src/getNextRobotStateAndWarnings/forDropTip.ts index 7ada991f2e4..d389b50f9ff 100644 --- a/step-generation/src/getNextRobotStateAndWarnings/forDropTip.ts +++ b/step-generation/src/getNextRobotStateAndWarnings/forDropTip.ts @@ -20,6 +20,7 @@ export function forDropTip( labwareId, useFullVolume: true, wellName, + robotStateAndWarnings, }) robotState.tipState.pipettes[pipetteId] = false } diff --git a/step-generation/src/getNextRobotStateAndWarnings/inPlaceCommandUpdates.ts b/step-generation/src/getNextRobotStateAndWarnings/inPlaceCommandUpdates.ts index e14b1b37344..18cb8ead615 100644 --- a/step-generation/src/getNextRobotStateAndWarnings/inPlaceCommandUpdates.ts +++ b/step-generation/src/getNextRobotStateAndWarnings/inPlaceCommandUpdates.ts @@ -27,6 +27,7 @@ export const forDispenseInPlace = ( prevLiquidState: robotState.liquidState, useFullVolume: false, volume, + robotStateAndWarnings, }) } @@ -42,6 +43,7 @@ export const forBlowOutInPlace = ( pipetteId, prevLiquidState: robotState.liquidState, useFullVolume: true, + robotStateAndWarnings, }) } @@ -59,5 +61,6 @@ export const forDropTipInPlace = ( prevLiquidState: robotState.liquidState, pipetteId, useFullVolume: true, + robotStateAndWarnings, }) } diff --git a/step-generation/src/robotStateSelectors.ts b/step-generation/src/robotStateSelectors.ts index b9dc676275d..4b1b0e9310e 100644 --- a/step-generation/src/robotStateSelectors.ts +++ b/step-generation/src/robotStateSelectors.ts @@ -1,4 +1,3 @@ -import assert from 'assert' // TODO: Ian 2019-04-18 move orderWells somewhere more general -- shared-data util? import min from 'lodash/min' import { @@ -77,7 +76,10 @@ export function _getNextTip(args: { return allWellsHaveTip ? orderedWells[0] : null } - assert(false, `Pipette ${pipetteId} has no channels/spec, cannot _getNextTip`) + console.assert( + false, + `Pipette ${pipetteId} has no channels/spec, cannot _getNextTip` + ) return null } interface NextTiprackInfo { @@ -89,7 +91,7 @@ interface NextTiprackInfo { } export function getNextTiprack( pipetteId: string, - tipRack: string, + tipRackUri: string, invariantContext: InvariantContext, robotState: RobotState, nozzles?: NozzleConfigurationStyle @@ -110,16 +112,14 @@ export function getNextTiprack( // filter out unmounted or non-compatible tiprack models const sortedTipracksIds = sortLabwareBySlot(robotState.labware).filter( labwareId => { - assert( + console.assert( invariantContext.labwareEntities[labwareId]?.labwareDefURI, `cannot getNextTiprack, no labware entity for "${labwareId}"` ) const isOnDeck = robotState.labware[labwareId].slot != null const labwareIdDefUri = invariantContext.labwareEntities[labwareId].labwareDefURI - const tipRackDefUri = - invariantContext.labwareEntities[tipRack].labwareDefURI - return isOnDeck && labwareIdDefUri === tipRackDefUri + return isOnDeck && labwareIdDefUri === tipRackUri } ) const is96Channel = pipetteEntity.spec.channels === 96 @@ -184,14 +184,13 @@ export function getNextTiprack( export function getPipetteWithTipMaxVol( pipetteId: string, invariantContext: InvariantContext, - tipRack: string + tipRackDefUri: string ): number { // NOTE: this fn assumes each pipette is assigned to exactly one tiprack type, // across the entire timeline const pipetteEntity = invariantContext.pipetteEntities[pipetteId] const pipetteMaxVol = pipetteEntity.spec.liquids.default.maxVolume const tiprackDef = pipetteEntity.tiprackLabwareDef - const tipRackDefUri = invariantContext.labwareEntities[tipRack].labwareDefURI let chosenTipRack = null for (const def of tiprackDef) { if (getLabwareDefURI(def) === tipRackDefUri) { @@ -202,7 +201,7 @@ export function getPipetteWithTipMaxVol( const tiprackTipVol = getTiprackVolume(chosenTipRack ?? tiprackDef[0]) if (!pipetteMaxVol || !tiprackTipVol) { - assert( + console.assert( false, `getPipetteEffectiveMaxVol expected tiprackMaxVol and pipette maxVolume to be > 0, got', ${pipetteMaxVol}, ${tiprackTipVol}` diff --git a/step-generation/src/types.ts b/step-generation/src/types.ts index 6cef80c43ed..e63360a3f27 100644 --- a/step-generation/src/types.ts +++ b/step-generation/src/types.ts @@ -539,9 +539,9 @@ export type ErrorType = | 'PIPETTE_HAS_TIP' | 'PIPETTE_VOLUME_EXCEEDED' | 'PIPETTING_INTO_COLUMN_4' + | 'POSSIBLE_PIPETTE_COLLISION' | 'REMOVE_96_CHANNEL_TIPRACK_ADAPTER' | 'TALL_LABWARE_EAST_WEST_OF_HEATER_SHAKER' - | 'TALL_LABWARE_WEST_OF_96_CHANNEL_LABWARE' | 'THERMOCYCLER_LID_CLOSED' | 'TIP_VOLUME_EXCEEDED' diff --git a/step-generation/src/utils/index.ts b/step-generation/src/utils/index.ts index ac363cbcd97..9c8ab222c57 100644 --- a/step-generation/src/utils/index.ts +++ b/step-generation/src/utils/index.ts @@ -20,6 +20,6 @@ export * from './commandCreatorArgsGetters' export * from './heaterShakerCollision' export * from './misc' export * from './movableTrashCommandsUtil' -export * from './ninetySixChannelCollision' +export * from './safePipetteMovements' export * from './wasteChuteCommandsUtil' export const uuid: () => string = uuidv4 diff --git a/step-generation/src/utils/ninetySixChannelCollision.ts b/step-generation/src/utils/ninetySixChannelCollision.ts deleted file mode 100644 index 7a2b7f3e0c1..00000000000 --- a/step-generation/src/utils/ninetySixChannelCollision.ts +++ /dev/null @@ -1,78 +0,0 @@ -import toNumber from 'lodash/toNumber' -import { getModuleDef2 } from '@opentrons/shared-data' -import type { RobotState, InvariantContext } from '../types' - -const SAFETY_MARGIN = 10 -const targetNumbers = ['2', '3', '4'] - -export const getIsTallLabwareWestOf96Channel = ( - robotState: RobotState, - invariantContext: InvariantContext, - sourceLabwareId: string, - pipetteId: string, - tipRackId: string -): boolean => { - const { labwareEntities, additionalEquipmentEntities } = invariantContext - const { labware: labwareState, tipState } = robotState - const pipetteHasTip = tipState.pipettes[pipetteId] - const tipLength = pipetteHasTip - ? labwareEntities[tipRackId].def.parameters.tipLength ?? 0 - : 0 - // early exit if source labware is the waste chute or trash bin - if (additionalEquipmentEntities[sourceLabwareId] != null) { - return false - } - - const labwareSlot = labwareState[sourceLabwareId].slot - const letter = labwareSlot.charAt(0) - const number = labwareSlot.charAt(1) - - if (targetNumbers.includes(number)) { - const westNumber = toNumber(number) - 1 - const westSlot = letter + westNumber - - const westLabwareState = Object.entries(labwareState).find( - ([id, labware]) => labware.slot === westSlot - ) - if (westLabwareState != null) { - const westLabwareId = westLabwareState[0] - if (labwareEntities[westLabwareId] == null) { - console.error( - `expected to find labware west of source labware but could not, with labware id ${westLabwareId}` - ) - } - if (labwareEntities[westLabwareId] != null) { - const westLabwareHeight = - labwareEntities[westLabwareId].def.dimensions.zDimension - const westLabwareSlot = robotState.labware[westLabwareId].slot - let adapterHeight: number = 0 - let moduleHeight: number = 0 - // if labware is on an adapter + or on an adapter + module - if (robotState.labware[westLabwareSlot] != null) { - const adapterSlot = robotState.labware[westLabwareSlot]?.slot - adapterHeight = - invariantContext.labwareEntities[westLabwareSlot]?.def.dimensions - .zDimension - const moduleModel = - invariantContext.moduleEntities[adapterSlot]?.model - const moduleDimensions = - moduleModel != null ? getModuleDef2(moduleModel)?.dimensions : null - moduleHeight = - moduleDimensions != null ? moduleDimensions.bareOverallHeight : 0 - // if labware is on a module - } else if (invariantContext.moduleEntities[westLabwareSlot] != null) { - const moduleModel = - invariantContext.moduleEntities[westLabwareSlot].model - moduleHeight = getModuleDef2(moduleModel).dimensions.bareOverallHeight - } - const totalHighestZ = westLabwareHeight + adapterHeight + moduleHeight - const sourceLabwareHeight = - labwareEntities[sourceLabwareId].def.dimensions.zDimension - - return totalHighestZ + SAFETY_MARGIN > sourceLabwareHeight + tipLength - } - } - } - - return false -} diff --git a/step-generation/src/utils/safePipetteMovements.ts b/step-generation/src/utils/safePipetteMovements.ts new file mode 100644 index 00000000000..8fa82fa585f --- /dev/null +++ b/step-generation/src/utils/safePipetteMovements.ts @@ -0,0 +1,377 @@ +import { + FLEX_ROBOT_TYPE, + THERMOCYCLER_MODULE_TYPE, + getAddressableAreaFromSlotId, + getDeckDefFromRobotType, + getFlexSurroundingSlots, + getModuleDef2, + getPositionFromSlotId, +} from '@opentrons/shared-data' +import type { + AddressableArea, + CoordinateTuple, + NozzleConfigurationStyle, +} from '@opentrons/shared-data' +import type { + RobotState, + InvariantContext, + PipetteEntity, + ModuleEntities, + LabwareEntity, +} from '../types' + +const A12_column_front_left_bound = { x: -11.03, y: 2 } +const A12_column_back_right_bound = { x: 526.77, y: 506.2 } +const PRIMARY_NOZZLE = 'A12' +const NOZZLE_CONFIGURATION = 'COLUMN' +const FLEX_TC_LID_COLLISION_ZONE = { + back_left: { x: -43.25, y: 454.9, z: 211.91 }, + front_right: { x: 128.75, y: 402, z: 211.91 }, +} +const FLEX_TC_LID_BACK_LEFT_PT = { + x: FLEX_TC_LID_COLLISION_ZONE.back_left.x, + y: FLEX_TC_LID_COLLISION_ZONE.back_left.y, + z: FLEX_TC_LID_COLLISION_ZONE.back_left.z, +} + +const FLEX_TC_LID_FRONT_RIGHT_PT = { + x: FLEX_TC_LID_COLLISION_ZONE.front_right.x, + y: FLEX_TC_LID_COLLISION_ZONE.front_right.y, + z: FLEX_TC_LID_COLLISION_ZONE.front_right.z, +} + +interface SlotInfo { + addressableArea: AddressableArea | null + position: CoordinateTuple | null +} +interface Point { + x: number + y: number + z?: number +} + +// check if nozzle(s) are inbounds +const getIsWithinPipetteExtents = ( + location: Point, + nozzleConfiguration: NozzleConfigurationStyle, + primaryNozzle: string +): boolean => { + if (nozzleConfiguration === 'COLUMN' && primaryNozzle === 'A12') { + const isWithinBounds = + A12_column_front_left_bound.x <= location.x && + location.x <= A12_column_back_right_bound.x && + A12_column_front_left_bound.y <= location.y && + location.y <= A12_column_back_right_bound.y + + return isWithinBounds + } else { + // TODO: Handle other configurations such as 8-channel partial tip, and eventually all pipettes. + return true + } +} + +// return pipette bounds at a sepcific position +const getPipetteBoundsAtSpecifiedMoveToPosition = ( + pipetteEntity: PipetteEntity, + tipLength: number, + destinationPosition: Point +): Point[] => { + const primaryNozzleOffset = + pipetteEntity.spec.nozzleMap != null + ? pipetteEntity.spec.nozzleMap.A1 + : pipetteEntity.spec.nozzleOffset + const primaryNozzlePosition = { + x: destinationPosition.x, + y: destinationPosition.y, + z: (destinationPosition.z ?? 0) + tipLength, + } + const pipetteBoundsOffsets = pipetteEntity.spec.pipetteBoundingBoxOffsets + const backLeftBound = { + x: + primaryNozzlePosition.x - + primaryNozzleOffset[0] + + pipetteBoundsOffsets.backLeftCorner[0], + y: + primaryNozzlePosition.y - + primaryNozzleOffset[1] + + pipetteBoundsOffsets.backLeftCorner[1], + z: + primaryNozzlePosition.z - + primaryNozzleOffset[2] + + pipetteBoundsOffsets.backLeftCorner[2], + } + const frontRightBound = { + x: + primaryNozzlePosition.x - + primaryNozzleOffset[0] + + pipetteBoundsOffsets.frontRightCorner[0], + y: + primaryNozzlePosition.y - + primaryNozzleOffset[1] + + pipetteBoundsOffsets.frontRightCorner[1], + z: + primaryNozzlePosition.z - + primaryNozzleOffset[2] + + pipetteBoundsOffsets.frontRightCorner[2], + } + + const backRightBound: Point = { + x: frontRightBound.x, + y: backLeftBound.y, + z: frontRightBound.z, + } + const frontLeftBound: Point = { + x: backLeftBound.x, + y: frontRightBound.y, + z: backLeftBound.z, + } + + return [backLeftBound, frontRightBound, backRightBound, frontLeftBound] +} + +// return whether the two provided rectangles are overlapping in the 2d space. +const getHasOverlappingRectangles = ( + rectangle1: Point[], + rectangle2: Point[] +): boolean => { + const xCoords = [ + rectangle1[0].x, + rectangle1[1].x, + rectangle2[0].x, + rectangle2[1].x, + ] + const xLengthRect1 = Math.abs(rectangle1[1].x - rectangle1[0].x) + const xLengthRect2 = Math.abs((rectangle2[1].x = rectangle2[0].x)) + const overlappingInX = + Math.abs(Math.max(...xCoords) - Math.min(...xCoords)) < + xLengthRect1 + xLengthRect2 + const yCoordinates = [ + rectangle1[0].y, + rectangle1[1].y, + rectangle2[0].y, + rectangle2[1].y, + ] + const yLengthRect1 = Math.abs(rectangle1[1].y - rectangle1[0].y) + const yLengthRect2 = Math.abs(rectangle2[1].y - rectangle2[0].y) + const overlappingInY = + Math.abs(Math.max(...yCoordinates) - Math.min(...yCoordinates)) < + yLengthRect1 + yLengthRect2 + + return overlappingInX && overlappingInY +} + +// check the highest Z-point of all items stacked given a deck slot (including modules, +// adapters, and modules on adapters) +const getHighestZInSlot = ( + robotState: RobotState, + invariantContext: InvariantContext, + labwareId: string +): number => { + const { modules, labware } = robotState + const { moduleEntities, labwareEntities } = invariantContext + if (modules[labwareId] != null) { + const moduleDimensions = getModuleDef2(moduleEntities[labwareId].model) + .dimensions + return ( + // labware + module + labwareEntities[labwareId].def.dimensions.zDimension + + moduleDimensions.bareOverallHeight + + (moduleDimensions.lidHeight ?? 0) + ) + } else if (labware[labwareId] != null) { + const adapterId = labware[labwareId].slot + if (labwareEntities[adapterId] != null) { + if (modules[adapterId] != null) { + const moduleDimensions = getModuleDef2(moduleEntities[adapterId].model) + .dimensions + return ( + // labware + adapter + module + labwareEntities[labwareId].def.dimensions.zDimension + + labwareEntities[adapterId].def.dimensions.zDimension + + moduleDimensions.bareOverallHeight + + (moduleDimensions.lidHeight ?? 0) + ) + } else { + return ( + // labware + adapter + labwareEntities[labwareId].def.dimensions.zDimension + + labwareEntities[adapterId].def.dimensions.zDimension + ) + } + } else { + // labware + return labwareEntities[labwareId].def.dimensions.zDimension + } + // shouldn't hit here! + } else { + console.error('something went wrong, this shoud not be hit') + return 0 + } +} + +// check if the slot overlaps with the pipette position +const getSlotHasPotentialCollidingObject = ( + pipetteBounds: Point[], + slotInfo: SlotInfo[], + robotState: RobotState, + invariantContext: InvariantContext, + labwareId: string +): boolean => { + for (const slot of slotInfo) { + const slotBounds = slot.addressableArea?.boundingBox + const slotPosition = slot.position + + // If slotPosition or slotBounds is null, continue to the next iteration + if (slotPosition == null || slotBounds == null) { + continue + } + + const backLeftCoords = { + x: slotPosition[0], + y: slotBounds.yDimension + slotPosition[1], + z: slotPosition[2], + } + const frontRightCoords = { + x: slotPosition[0] + slotBounds.xDimension, + y: slotPosition[1], + z: slotPosition[2], + } + // Check for overlapping rectangles and pipette z-coordinate if slot overlaps with pipette bounds + if ( + getHasOverlappingRectangles( + [pipetteBounds[0], pipetteBounds[1]], + [backLeftCoords, frontRightCoords] + ) && + pipetteBounds[0].z != null + ) { + const highestZInSlot = getHighestZInSlot( + robotState, + invariantContext, + labwareId + ) + return highestZInSlot >= pipetteBounds[0]?.z + } + } + return false +} + +const getWillCollideWithThermocyclerLid = ( + pipetteBounds: Point[], + moduleEntities: ModuleEntities +): boolean => { + if ( + Object.values(moduleEntities).find( + module => module.type === THERMOCYCLER_MODULE_TYPE + ) + ) { + return ( + getHasOverlappingRectangles( + [FLEX_TC_LID_BACK_LEFT_PT, FLEX_TC_LID_FRONT_RIGHT_PT], + [pipetteBounds[0], pipetteBounds[1]] + ) && pipetteBounds[0].x <= FLEX_TC_LID_BACK_LEFT_PT.z + ) + } else { + return false + } +} + +const getWellPosition = ( + labwareEntity: LabwareEntity, + wellLocationOffset: Point +): Point => { + const { dimensions: wellDimensions, cornerOffsetFromSlot } = labwareEntity.def + + // getting location from the bottom of the well since PD only supports aspirate/dispense from bottom + // note: api includes calibration data here which PD does not have knowledge of at the moment + return { + x: + cornerOffsetFromSlot.x + wellLocationOffset.x + wellDimensions.xDimension, + y: + cornerOffsetFromSlot.y + wellLocationOffset.y + wellDimensions.yDimension, + z: + cornerOffsetFromSlot.z + + (wellLocationOffset.z ?? 0) + + wellDimensions.zDimension, + } +} + +// util to use in step-generation for if the pipette movement is safe +export const getIsSafePipetteMovement = ( + robotState: RobotState, + invariantContext: InvariantContext, + pipetteId: string, + labwareId: string, + tipRackDefURI: string, + wellLocationOffset: Point +): boolean => { + const deckDefinition = getDeckDefFromRobotType(FLEX_ROBOT_TYPE) + const { + pipetteEntities, + labwareEntities, + additionalEquipmentEntities, + moduleEntities, + } = invariantContext + const { labware: labwareState, tipState } = robotState + + // early exit if labwareId is a trashBin or wasteChute + if (labwareEntities[labwareId] == null) { + return true + } + const tiprackTipLength = Object.values(labwareEntities).find( + labwareEntity => labwareEntity.labwareDefURI === tipRackDefURI + )?.def.parameters.tipLength + + const stagingAreaSlots = Object.values(additionalEquipmentEntities) + .filter(ae => ae.name === 'stagingArea') + .map(stagingArea => stagingArea.location as string) + const pipetteEntity = pipetteEntities[pipetteId] + const pipetteHasTip = tipState.pipettes[pipetteId] + const tipLength = pipetteHasTip ? tiprackTipLength ?? 0 : 0 + const wellLocationPoint = getWellPosition( + labwareEntities[labwareId], + wellLocationOffset + ) + + const isWithinPipetteExtents = getIsWithinPipetteExtents( + wellLocationPoint, + // TODO(jr, 4/22/24): PD only supports A12 as a primary nozzle for now + // and only for 96-channel column pick up + NOZZLE_CONFIGURATION, + PRIMARY_NOZZLE + ) + if (!isWithinPipetteExtents) { + return false + } else { + const labwareSlot = labwareState[labwareId].slot + const pipetteBoundsAtWellLocation = getPipetteBoundsAtSpecifiedMoveToPosition( + pipetteEntity, + tipLength, + wellLocationOffset + ) + const surroundingSlots = getFlexSurroundingSlots( + labwareSlot, + stagingAreaSlots + ) + const slotInfos: SlotInfo[] = surroundingSlots.map(slot => { + const addressableArea = getAddressableAreaFromSlotId(slot, deckDefinition) + const position = getPositionFromSlotId(slot, deckDefinition) + return { + addressableArea, + position, + } + }) + return ( + !getWillCollideWithThermocyclerLid( + pipetteBoundsAtWellLocation, + moduleEntities + ) && + !getSlotHasPotentialCollidingObject( + pipetteBoundsAtWellLocation, + slotInfos, + robotState, + invariantContext, + labwareId + ) + ) + } +} diff --git a/system-server/Pipfile b/system-server/Pipfile index 78c13a0ff55..d1ce7f43f6a 100644 --- a/system-server/Pipfile +++ b/system-server/Pipfile @@ -14,6 +14,7 @@ pydantic = "==1.10.12" importlib-metadata = ">=4.13.0,<5" sqlalchemy = "==1.4.51" pyjwt = "==2.6.0" +filetype = "==1.2.0" systemd-python = { version = "==234", markers="sys_platform == 'linux'" } server-utils = {editable = true, path = "./../server-utils"} system_server = {path = ".", editable = true} diff --git a/system-server/Pipfile.lock b/system-server/Pipfile.lock index bbaa48e640c..d7d315362f2 100644 --- a/system-server/Pipfile.lock +++ b/system-server/Pipfile.lock @@ -50,6 +50,14 @@ "markers": "python_version >= '3.7'", "version": "==0.99.1" }, + "filetype": { + "hashes": [ + "sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb", + "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25" + ], + "index": "pypi", + "version": "==1.2.0" + }, "h11": { "hashes": [ "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", @@ -231,12 +239,12 @@ }, "typing-extensions": { "hashes": [ - "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", - "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0", + "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.9.0" + "version": "==4.11.0" }, "uvicorn": { "hashes": [ diff --git a/system-server/settings_schema.json b/system-server/settings_schema.json index c16b2c49621..7916f39dcf9 100644 --- a/system-server/settings_schema.json +++ b/system-server/settings_schema.json @@ -9,6 +9,19 @@ "default": "/var/lib/opentrons-system-server/", "env_names": ["ot_system_server_persistence_directory"], "type": "string" + }, + "oem_mode_enabled": { + "title": "OEM Mode Enabled", + "description": "A flag used to change the default splash screen on system startup. If this flag is disabled (default), the Opentrons loading video will be shown. If this flag is enabled but `oem_mode_splash_custom` is not set, then the default OEM Mode splash screen will be shown. If this flag is enabled and `oem_mode_splash_custom` is set to a PNG filepath, the custom splash screen will be shown.", + "default": false, + "env_names": ["ot_system_server_oem_mode_enabled"], + "type": "bool" + }, + "oem_mode_splash_custom": { + "description": "The filepath of the PNG image used as the custom splash screen. Read the description of the `oem_mode_enabled` flag to know how the splash screen changes when the flag is enabled/disabled.", + "default": null, + "env_names": ["ot_system_server_oem_mode_splash_custom"], + "type": "string" } }, "additionalProperties": false diff --git a/system-server/system_server/settings/__init__.py b/system-server/system_server/settings/__init__.py index b2db58a6389..feae773340f 100644 --- a/system-server/system_server/settings/__init__.py +++ b/system-server/system_server/settings/__init__.py @@ -1,6 +1,10 @@ """system_server.settings: Provides an interface to get server settings.""" -from .settings import get_settings, SystemServerSettings +from .settings import ( + save_settings, + get_settings, + SystemServerSettings, +) -__all__ = ["get_settings", "SystemServerSettings"] +__all__ = ["save_settings", "get_settings", "SystemServerSettings"] diff --git a/system-server/system_server/settings/settings.py b/system-server/system_server/settings/settings.py index a042b76b91d..32e34079ebd 100644 --- a/system-server/system_server/settings/settings.py +++ b/system-server/system_server/settings/settings.py @@ -1,27 +1,20 @@ """System server configuration options.""" import typing -import logging from functools import lru_cache from pydantic import BaseSettings, Field -from dotenv import load_dotenv - -log = logging.getLogger(__name__) +from dotenv import load_dotenv, set_key @lru_cache(maxsize=1) def get_settings() -> "SystemServerSettings": """Get the settings.""" - update_from_dotenv() - return SystemServerSettings() - - -def update_from_dotenv() -> None: - """Get the location of the settings file.""" env = Environment().dot_env_path if env: load_dotenv(env) + return SystemServerSettings() + class Environment(BaseSettings): """Environment related settings.""" @@ -56,7 +49,44 @@ class SystemServerSettings(BaseSettings): ), ) + oem_mode_enabled: typing.Optional[bool] = Field( + default=False, + description=( + "A flag used to change the default splash screen on system startup." + " If this flag is disabled (default), the Opentrons loading video will be shown." + " If this flag is enabled but `oem_mode_splash_custom` is not set," + " then the default OEM Mode splash screen will be shown." + " If this flag is enabled and `oem_mode_splash_custom` is set to a" + " PNG filepath, the custom splash screen will be shown." + ), + ) + + oem_mode_splash_custom: typing.Optional[str] = Field( + default=None, + description=( + "The filepath of the PNG image used as the custom splash screen." + " Read the description of the `oem_mode_enabled` flag to know how" + " the splash screen changes when the flag is enabled/disabled." + ), + ) + class Config: """Prefix configuration for environment variables.""" + env_file = Environment().dot_env_path env_prefix = "OT_SYSTEM_SERVER_" + + +def save_settings(settings: SystemServerSettings) -> bool: + """Save the settings to the dotenv file.""" + env_path = Environment().dot_env_path + env_path = env_path or f"{settings.persistence_directory}/system.env" + prefix = settings.Config.env_prefix + try: + for key, val in settings.dict().items(): + name = f"{prefix}{key}" + value = str(val) if val is not None else "" + set_key(env_path, name, value) + return True + except (IOError, ValueError): + return False diff --git a/system-server/system_server/system/oem_mode/__init__.py b/system-server/system_server/system/oem_mode/__init__.py new file mode 100644 index 00000000000..ddbd3555ebf --- /dev/null +++ b/system-server/system_server/system/oem_mode/__init__.py @@ -0,0 +1,5 @@ +"""OEM Mode endpoint.""" + +from .router import oem_mode_router + +__all__ = ["oem_mode_router"] diff --git a/system-server/system_server/system/oem_mode/dependencies.py b/system-server/system_server/system/oem_mode/dependencies.py new file mode 100644 index 00000000000..b59bb825024 --- /dev/null +++ b/system-server/system_server/system/oem_mode/dependencies.py @@ -0,0 +1,21 @@ +"""Dependencies for /system/register endpoints.""" +from system_server.jwt import Registrant +from fastapi import Query + + +def create_registrant( + subject: str = Query( + ..., description="Identifies the human intending to register with the robot" + ), + agent: str = Query(..., description="Identifies the app type making the request"), + agentId: str = Query( + ..., description="A unique identifier for the instance of the agent" + ), +) -> Registrant: + """Define a unique Registrant to create a registration token for. + + A registrant is defined by a set of unique identifiers that remain + persistent indefinitely for the same person using the same method of + access to the system. + """ + return Registrant(subject=subject, agent=agent, agent_id=agentId) diff --git a/system-server/system_server/system/oem_mode/models.py b/system-server/system_server/system/oem_mode/models.py new file mode 100644 index 00000000000..192e1ce4fa6 --- /dev/null +++ b/system-server/system_server/system/oem_mode/models.py @@ -0,0 +1,9 @@ +"""Models for /system/oem_mode.""" + +from pydantic import BaseModel, Field + + +class EnableOEMMode(BaseModel): + """Enable OEM Mode model.""" + + enable: bool = Field(..., description="Enable or Disable OEM Mode.") diff --git a/system-server/system_server/system/oem_mode/router.py b/system-server/system_server/system/oem_mode/router.py new file mode 100644 index 00000000000..1b7119b6127 --- /dev/null +++ b/system-server/system_server/system/oem_mode/router.py @@ -0,0 +1,142 @@ +"""Router for /system/register endpoint.""" + +import re +import os +import filetype # type: ignore[import-untyped] +from fastapi import ( + APIRouter, + Depends, + status, + Response, + UploadFile, + File, + HTTPException, +) +from pathlib import Path + +from .models import EnableOEMMode +from ...settings import SystemServerSettings, get_settings, save_settings + + +# regex to sanitize the filename +FILENAME_REGEX = re.compile(r"[^a-zA-Z0-9-.]") + + +oem_mode_router = APIRouter() + + +@oem_mode_router.put( + "/system/oem_mode/enable", + summary="Enable or Disable OEM Mode for this robot.", + responses={ + status.HTTP_200_OK: {"message": "OEM Mode changed successfully."}, + status.HTTP_400_BAD_REQUEST: {"message": "OEM Mode did not changed."}, + status.HTTP_500_INTERNAL_SERVER_ERROR: { + "message": "OEM Mode unhandled exception." + }, + }, +) +async def enable_oem_mode_endpoint( + response: Response, + enableRequest: EnableOEMMode, + settings: SystemServerSettings = Depends(get_settings), +) -> Response: + """Router for /system/oem_mode/enable endpoint.""" + enable = enableRequest.enable + try: + settings.oem_mode_enabled = enable + success = save_settings(settings) + response.status_code = ( + status.HTTP_200_OK if success else status.HTTP_400_BAD_REQUEST + ) + except Exception: + response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR + return response + + +@oem_mode_router.post( + "/system/oem_mode/upload_splash", + summary="Upload an image to be used as the boot up splash screen.", + responses={ + status.HTTP_201_CREATED: {"message": "OEM Mode splash screen uploaded"}, + status.HTTP_400_BAD_REQUEST: {"message": "OEM Mode splash screen not set"}, + status.HTTP_413_REQUEST_ENTITY_TOO_LARGE: { + "message": "File is larger than 5mb" + }, + status.HTTP_415_UNSUPPORTED_MEDIA_TYPE: {"message": "Invalid file type"}, + status.HTTP_500_INTERNAL_SERVER_ERROR: { + "message": "OEM Mode splash unhandled exception." + }, + }, +) +async def upload_splash_image( + response: Response, + file: UploadFile = File(...), + settings: SystemServerSettings = Depends(get_settings), +) -> Response: + """Router for /system/oem_mode/upload_splash endpoint.""" + # Make sure oem mode is enabled before this request + if not settings.oem_mode_enabled: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="OEM Mode needs to be enabled to upload splash image.", + ) + + # Get the file info + file_info = filetype.guess(file.file) + if file_info is None or not file.filename: + raise HTTPException( + status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE, + detail="Unable to determine file type", + ) + + # Only accept PNG files + accepted_file_types = ["image/png", "png"] + content_type = file_info.extension.lower() + if ( + file.content_type not in accepted_file_types + or content_type not in accepted_file_types + ): + raise HTTPException( + status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE, + detail="Unsupported file type", + ) + + file_size = 0 + for chunk in file.file: + file_size += len(chunk) + if file_size > 5 * 1024 * 1024: # 5MB + raise HTTPException( + status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE, + detail="File is larger than 5mb.", + ) + + # TODO: Validate image dimensions + + # return the pointer back to the starting point so that the next read starts from the starting point + await file.seek(0) + + try: + # Remove the old image if exists + if settings.oem_mode_splash_custom: + os.unlink(settings.oem_mode_splash_custom) + + # sanitize the filename + sanatized_filename = FILENAME_REGEX.sub("_", file.filename) + filename = f"{Path(sanatized_filename).stem}.{content_type}" + + # file is valid, save to final location + filepath = f"{settings.persistence_directory}/{filename}" + with open(filepath, "wb+") as f: + f.write(file.file.read()) + + # store the file location to settings and save the dotenv + settings.oem_mode_splash_custom = filepath + success = save_settings(settings) + response.status_code = ( + status.HTTP_201_CREATED if success else status.HTTP_400_BAD_REQUEST + ) + except Exception: + response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR + + return response diff --git a/system-server/system_server/system/router.py b/system-server/system_server/system/router.py index 0ae868c5f51..b138a1d0ed6 100644 --- a/system-server/system_server/system/router.py +++ b/system-server/system_server/system/router.py @@ -3,6 +3,7 @@ from .register.router import register_router from .authorize.router import authorize_router from .connected.router import connected_router +from .oem_mode.router import oem_mode_router system_router = APIRouter() @@ -11,3 +12,5 @@ system_router.include_router(router=authorize_router) system_router.include_router(router=connected_router) + +system_router.include_router(router=oem_mode_router) diff --git a/system-server/tests/integration/resources/oem_mode_custom.png b/system-server/tests/integration/resources/oem_mode_custom.png new file mode 100644 index 00000000000..14cf4ac12bd Binary files /dev/null and b/system-server/tests/integration/resources/oem_mode_custom.png differ diff --git a/system-server/tests/integration/resources/oem_mode_wrong_dimensions.png b/system-server/tests/integration/resources/oem_mode_wrong_dimensions.png new file mode 100644 index 00000000000..2cc51a01cb0 Binary files /dev/null and b/system-server/tests/integration/resources/oem_mode_wrong_dimensions.png differ diff --git a/system-server/tests/integration/resources/oem_mode_wrong_image_type.jpeg b/system-server/tests/integration/resources/oem_mode_wrong_image_type.jpeg new file mode 100644 index 00000000000..aa95d031d93 Binary files /dev/null and b/system-server/tests/integration/resources/oem_mode_wrong_image_type.jpeg differ diff --git a/system-server/tests/integration/test_oem_mode.tavern.yaml b/system-server/tests/integration/test_oem_mode.tavern.yaml new file mode 100644 index 00000000000..9778495c6c3 --- /dev/null +++ b/system-server/tests/integration/test_oem_mode.tavern.yaml @@ -0,0 +1,124 @@ +--- +test_name: Test enable/disable OEM Mode +marks: + - usefixtures: + - run_server +stages: + - name: PUT first request + request: &enable_oem_mode_first + url: "{host:s}:{port:d}/system/oem_mode/enable" + json: + enable: true + method: PUT + headers: + content-type: application/json + response: + status_code: 200 + - name: PUT second request + request: &enable_oem_mode_second + url: "{host:s}:{port:d}/system/oem_mode/enable" + json: + enable: false + method: PUT + headers: + content-type: application/json + response: + status_code: 200 + - name: PUT third request + request: &enable_oem_mode_third + url: "{host:s}:{port:d}/system/oem_mode/enable" + json: + wrong_key: false + method: PUT + headers: + content-type: application/json + response: + status_code: 422 +--- +test_name: Upload, and validate a good image for OEM Mode + +marks: + - usefixtures: + - run_server +stages: + - name: Enable OEM Mode + request: + url: "{host:s}:{port:d}/system/oem_mode/enable" + method: PUT + json: + "enable": true + - name: Upload PNG Image + request: &upload_splash_first + url: "{host:s}:{port:d}/system/oem_mode/upload_splash" + method: POST + files: + file: 'tests/integration/resources/oem_mode_custom.png' + response: + status_code: 201 + +--- +test_name: Dont process upload_splash request if oem mode is disabled + +marks: + - usefixtures: + - run_server + +stages: + - name: Disable OEM Mode + request: + url: "{host:s}:{port:d}/system/oem_mode/enable" + method: PUT + json: + "enable": false + - name: Upload PNG Image + request: + url: "{host:s}:{port:d}/system/oem_mode/upload_splash" + method: POST + files: + file: 'tests/integration/resources/oem_mode_custom.png' + response: + status_code: 403 + - name: Enable OEM Mode + request: + url: "{host:s}:{port:d}/system/oem_mode/enable" + method: PUT + json: + "enable": true + - name: Upload PNG Image + request: + url: "{host:s}:{port:d}/system/oem_mode/upload_splash" + method: POST + files: + file: 'tests/integration/resources/oem_mode_custom.png' + response: + status_code: 201 +--- +test_name: Validate the image before processing + +marks: + - usefixtures: + - run_server + +stages: + - name: Enable OEM Mode + request: + url: "{host:s}:{port:d}/system/oem_mode/enable" + method: PUT + json: + "enable": true + - name: Upload non-PNG Image + request: + url: "{host:s}:{port:d}/system/oem_mode/upload_splash" + method: POST + files: + file: 'tests/integration/resources/oem_mode_wrong_image_type.jpeg' + response: + status_code: 415 + - name: Upload a PNG Image + request: + url: "{host:s}:{port:d}/system/oem_mode/upload_splash" + method: POST + files: + file: 'tests/integration/resources/oem_mode_custom.png' + response: + status_code: 201 diff --git a/test-data-generation/.flake8 b/test-data-generation/.flake8 new file mode 100644 index 00000000000..4aa1c02d7aa --- /dev/null +++ b/test-data-generation/.flake8 @@ -0,0 +1,25 @@ +[flake8] + +# max cyclomatic complexity +max-complexity = 9 + +extend-ignore = + # defer formatting concerns to black + # E203: space around `:` operator + # E501: maximum line length + E203, + E501, + # do not require type annotations for self nor cls + ANN101, + ANN102 + # do not require docstring for __init__, put them on the class + D107, + +# configure flake8-docstrings +# https://pypi.org/project/flake8-docstrings/ +docstring-convention = google + +noqa-require-code = true + +per-file-ignores = + setup.py:ANN,D \ No newline at end of file diff --git a/test-data-generation/Makefile b/test-data-generation/Makefile new file mode 100644 index 00000000000..a4818b00ab1 --- /dev/null +++ b/test-data-generation/Makefile @@ -0,0 +1,37 @@ +include ../scripts/python.mk + +.PHONY: lint +lint: + $(python) -m black --check . + $(python) -m flake8 . + $(python) -m mypy . + +.PHONY: format +format: + $(python) -m black . + +.PHONY: setup +setup: + $(pipenv) sync --dev + +.PHONY: teardown +teardown: + $(pipenv) --rm + +.PHONY: clean +clean: + rm -rf build dist *.egg-info .mypy_cache .pytest_cache src/test_data_generation.egg-info + +.PHONY: wheel +wheel: + $(python) setup.py $(wheel_opts) bdist_wheel + rm -rf build + +.PHONY: test +test: + $(pytest) tests \ + -s \ + --hypothesis-show-statistics \ + --hypothesis-verbosity=normal \ + --hypothesis-explain \ + -vvv \ No newline at end of file diff --git a/test-data-generation/Pipfile b/test-data-generation/Pipfile new file mode 100644 index 00000000000..758bcddacb7 --- /dev/null +++ b/test-data-generation/Pipfile @@ -0,0 +1,20 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[packages] +pytest = "==7.4.3" +black = "==23.11.0" +mypy = "==1.7.1" +flake8 = "==7.0.0" +flake8-annotations = "~=3.0.1" +flake8-docstrings = "~=1.7.0" +flake8-noqa = "~=1.4.0" +hypothesis = "==6.96.1" +opentrons-shared-data = {file = "../shared-data/python", editable = true} +test-data-generation = {file = ".", editable = true} + + +[requires] +python_version = "3.10" diff --git a/test-data-generation/Pipfile.lock b/test-data-generation/Pipfile.lock new file mode 100644 index 00000000000..1b223033d61 --- /dev/null +++ b/test-data-generation/Pipfile.lock @@ -0,0 +1,365 @@ +{ + "_meta": { + "hash": { + "sha256": "1df89f797a19f2c0febc582e7452a52858511cece041f9f612a59d35628226c2" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.10" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "attrs": { + "hashes": [ + "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", + "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + ], + "markers": "python_version >= '3.7'", + "version": "==23.2.0" + }, + "black": { + "hashes": [ + "sha256:250d7e60f323fcfc8ea6c800d5eba12f7967400eb6c2d21ae85ad31c204fb1f4", + "sha256:2a9acad1451632021ee0d146c8765782a0c3846e0e0ea46659d7c4f89d9b212b", + "sha256:412f56bab20ac85927f3a959230331de5614aecda1ede14b373083f62ec24e6f", + "sha256:421f3e44aa67138ab1b9bfbc22ee3780b22fa5b291e4db8ab7eee95200726b07", + "sha256:45aa1d4675964946e53ab81aeec7a37613c1cb71647b5394779e6efb79d6d187", + "sha256:4c44b7211a3a0570cc097e81135faa5f261264f4dfaa22bd5ee2875a4e773bd6", + "sha256:4c68855825ff432d197229846f971bc4d6666ce90492e5b02013bcaca4d9ab05", + "sha256:5133f5507007ba08d8b7b263c7aa0f931af5ba88a29beacc4b2dc23fcefe9c06", + "sha256:54caaa703227c6e0c87b76326d0862184729a69b73d3b7305b6288e1d830067e", + "sha256:58e5f4d08a205b11800332920e285bd25e1a75c54953e05502052738fe16b3b5", + "sha256:698c1e0d5c43354ec5d6f4d914d0d553a9ada56c85415700b81dc90125aac244", + "sha256:6c1cac07e64433f646a9a838cdc00c9768b3c362805afc3fce341af0e6a9ae9f", + "sha256:760415ccc20f9e8747084169110ef75d545f3b0932ee21368f63ac0fee86b221", + "sha256:7f622b6822f02bfaf2a5cd31fdb7cd86fcf33dab6ced5185c35f5db98260b055", + "sha256:cf57719e581cfd48c4efe28543fea3d139c6b6f1238b3f0102a9c73992cbb479", + "sha256:d136ef5b418c81660ad847efe0e55c58c8208b77a57a28a503a5f345ccf01394", + "sha256:dbea0bb8575c6b6303cc65017b46351dc5953eea5c0a59d7b7e3a2d2f433a911", + "sha256:fc7f6a44d52747e65a02558e1d807c82df1d66ffa80a601862040a43ec2e3142" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==23.11.0" + }, + "click": { + "hashes": [ + "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", + "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de" + ], + "markers": "python_version >= '3.7'", + "version": "==8.1.7" + }, + "exceptiongroup": { + "hashes": [ + "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad", + "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16" + ], + "markers": "python_version < '3.11'", + "version": "==1.2.1" + }, + "flake8": { + "hashes": [ + "sha256:33f96621059e65eec474169085dc92bf26e7b2d47366b70be2f67ab80dc25132", + "sha256:a6dfbb75e03252917f2473ea9653f7cd799c3064e54d4c8140044c5c065f53c3" + ], + "index": "pypi", + "markers": "python_full_version >= '3.8.1'", + "version": "==7.0.0" + }, + "flake8-annotations": { + "hashes": [ + "sha256:af78e3216ad800d7e144745ece6df706c81b3255290cbf870e54879d495e8ade", + "sha256:ff37375e71e3b83f2a5a04d443c41e2c407de557a884f3300a7fa32f3c41cb0a" + ], + "index": "pypi", + "markers": "python_full_version >= '3.8.1'", + "version": "==3.0.1" + }, + "flake8-docstrings": { + "hashes": [ + "sha256:4c8cc748dc16e6869728699e5d0d685da9a10b0ea718e090b1ba088e67a941af", + "sha256:51f2344026da083fc084166a9353f5082b01f72901df422f74b4d953ae88ac75" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==1.7.0" + }, + "flake8-noqa": { + "hashes": [ + "sha256:4465e16a19be433980f6f563d05540e2e54797eb11facb9feb50fed60624dc45", + "sha256:771765ab27d1efd157528379acd15131147f9ae578a72d17fb432ca197881243" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==1.4.0" + }, + "hypothesis": { + "hashes": [ + "sha256:848ea0952f0bdfd02eac59e41b03f1cbba8fa2cffeffa8db328bbd6cfe159974", + "sha256:955a57e56be4607c81c17ca53e594af54aadeed91e07b88bb7f84e8208ea7739" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==6.96.1" + }, + "iniconfig": { + "hashes": [ + "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", + "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" + ], + "markers": "python_version >= '3.7'", + "version": "==2.0.0" + }, + "jsonschema": { + "hashes": [ + "sha256:0f864437ab8b6076ba6707453ef8f98a6a0d512a80e93f8abdb676f737ecb60d", + "sha256:a870ad254da1a8ca84b6a2905cac29d265f805acc57af304784962a2aa6508f6" + ], + "markers": "python_version >= '3.7'", + "version": "==4.17.3" + }, + "mccabe": { + "hashes": [ + "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", + "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e" + ], + "markers": "python_version >= '3.6'", + "version": "==0.7.0" + }, + "mypy": { + "hashes": [ + "sha256:12cce78e329838d70a204293e7b29af9faa3ab14899aec397798a4b41be7f340", + "sha256:1484b8fa2c10adf4474f016e09d7a159602f3239075c7bf9f1627f5acf40ad49", + "sha256:204e0d6de5fd2317394a4eff62065614c4892d5a4d1a7ee55b765d7a3d9e3f82", + "sha256:2643d145af5292ee956aa0a83c2ce1038a3bdb26e033dadeb2f7066fb0c9abce", + "sha256:2c6e4464ed5f01dc44dc9821caf67b60a4e5c3b04278286a85c067010653a0eb", + "sha256:2f7f6985d05a4e3ce8255396df363046c28bea790e40617654e91ed580ca7c51", + "sha256:31902408f4bf54108bbfb2e35369877c01c95adc6192958684473658c322c8a5", + "sha256:40716d1f821b89838589e5b3106ebbc23636ffdef5abc31f7cd0266db936067e", + "sha256:4b901927f16224d0d143b925ce9a4e6b3a758010673eeded9b748f250cf4e8f7", + "sha256:4fc3d14ee80cd22367caaaf6e014494415bf440980a3045bf5045b525680ac33", + "sha256:5cf3f0c5ac72139797953bd50bc6c95ac13075e62dbfcc923571180bebb662e9", + "sha256:6dbdec441c60699288adf051f51a5d512b0d818526d1dcfff5a41f8cd8b4aaf1", + "sha256:72cf32ce7dd3562373f78bd751f73c96cfb441de147cc2448a92c1a308bd0ca6", + "sha256:75aa828610b67462ffe3057d4d8a4112105ed211596b750b53cbfe182f44777a", + "sha256:75c4d2a6effd015786c87774e04331b6da863fc3fc4e8adfc3b40aa55ab516fe", + "sha256:78e25b2fd6cbb55ddfb8058417df193f0129cad5f4ee75d1502248e588d9e0d7", + "sha256:84860e06ba363d9c0eeabd45ac0fde4b903ad7aa4f93cd8b648385a888e23200", + "sha256:8c5091ebd294f7628eb25ea554852a52058ac81472c921150e3a61cdd68f75a7", + "sha256:944bdc21ebd620eafefc090cdf83158393ec2b1391578359776c00de00e8907a", + "sha256:9c7ac372232c928fff0645d85f273a726970c014749b924ce5710d7d89763a28", + "sha256:d9b338c19fa2412f76e17525c1b4f2c687a55b156320acb588df79f2e6fa9fea", + "sha256:ee5d62d28b854eb61889cde4e1dbc10fbaa5560cb39780c3995f6737f7e82120", + "sha256:f2c2521a8e4d6d769e3234350ba7b65ff5d527137cdcde13ff4d99114b0c8e7d", + "sha256:f6efc9bd72258f89a3816e3a98c09d36f079c223aa345c659622f056b760ab42", + "sha256:f7c5d642db47376a0cc130f0de6d055056e010debdaf0707cd2b0fc7e7ef30ea", + "sha256:fcb6d9afb1b6208b4c712af0dafdc650f518836065df0d4fb1d800f5d6773db2", + "sha256:fcd2572dd4519e8a6642b733cd3a8cfc1ef94bafd0c1ceed9c94fe736cb65b6a" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==1.7.1" + }, + "mypy-extensions": { + "hashes": [ + "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", + "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782" + ], + "markers": "python_version >= '3.5'", + "version": "==1.0.0" + }, + "opentrons-shared-data": { + "editable": true, + "file": "../shared-data/python", + "markers": "python_version >= '3.8'" + }, + "packaging": { + "hashes": [ + "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", + "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9" + ], + "markers": "python_version >= '3.7'", + "version": "==24.0" + }, + "pathspec": { + "hashes": [ + "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", + "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712" + ], + "markers": "python_version >= '3.8'", + "version": "==0.12.1" + }, + "platformdirs": { + "hashes": [ + "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068", + "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768" + ], + "markers": "python_version >= '3.8'", + "version": "==4.2.0" + }, + "pluggy": { + "hashes": [ + "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981", + "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be" + ], + "markers": "python_version >= '3.8'", + "version": "==1.4.0" + }, + "pycodestyle": { + "hashes": [ + "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f", + "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67" + ], + "markers": "python_version >= '3.8'", + "version": "==2.11.1" + }, + "pydantic": { + "hashes": [ + "sha256:005655cabc29081de8243126e036f2065bd7ea5b9dff95fde6d2c642d39755de", + "sha256:0d142fa1b8f2f0ae11ddd5e3e317dcac060b951d605fda26ca9b234b92214986", + "sha256:22ed12ee588b1df028a2aa5d66f07bf8f8b4c8579c2e96d5a9c1f96b77f3bb55", + "sha256:2746189100c646682eff0bce95efa7d2e203420d8e1c613dc0c6b4c1d9c1fde4", + "sha256:28e552a060ba2740d0d2aabe35162652c1459a0b9069fe0db7f4ee0e18e74d58", + "sha256:3287e1614393119c67bd4404f46e33ae3be3ed4cd10360b48d0a4459f420c6a3", + "sha256:3350f527bb04138f8aff932dc828f154847fbdc7a1a44c240fbfff1b57f49a12", + "sha256:3453685ccd7140715e05f2193d64030101eaad26076fad4e246c1cc97e1bb30d", + "sha256:394f08750bd8eaad714718812e7fab615f873b3cdd0b9d84e76e51ef3b50b6b7", + "sha256:4e316e54b5775d1eb59187f9290aeb38acf620e10f7fd2f776d97bb788199e53", + "sha256:50f1666a9940d3d68683c9d96e39640f709d7a72ff8702987dab1761036206bb", + "sha256:51d405b42f1b86703555797270e4970a9f9bd7953f3990142e69d1037f9d9e51", + "sha256:584f2d4c98ffec420e02305cf675857bae03c9d617fcfdc34946b1160213a948", + "sha256:5e09c19df304b8123938dc3c53d3d3be6ec74b9d7d0d80f4f4b5432ae16c2022", + "sha256:676ed48f2c5bbad835f1a8ed8a6d44c1cd5a21121116d2ac40bd1cd3619746ed", + "sha256:67f1a1fb467d3f49e1708a3f632b11c69fccb4e748a325d5a491ddc7b5d22383", + "sha256:6a51a1dd4aa7b3f1317f65493a182d3cff708385327c1c82c81e4a9d6d65b2e4", + "sha256:6bd7030c9abc80134087d8b6e7aa957e43d35714daa116aced57269a445b8f7b", + "sha256:75279d3cac98186b6ebc2597b06bcbc7244744f6b0b44a23e4ef01e5683cc0d2", + "sha256:7ac9237cd62947db00a0d16acf2f3e00d1ae9d3bd602b9c415f93e7a9fc10528", + "sha256:7ea210336b891f5ea334f8fc9f8f862b87acd5d4a0cbc9e3e208e7aa1775dabf", + "sha256:82790d4753ee5d00739d6cb5cf56bceb186d9d6ce134aca3ba7befb1eedbc2c8", + "sha256:92229f73400b80c13afcd050687f4d7e88de9234d74b27e6728aa689abcf58cc", + "sha256:9bea1f03b8d4e8e86702c918ccfd5d947ac268f0f0cc6ed71782e4b09353b26f", + "sha256:a980a77c52723b0dc56640ced396b73a024d4b74f02bcb2d21dbbac1debbe9d0", + "sha256:af9850d98fc21e5bc24ea9e35dd80a29faf6462c608728a110c0a30b595e58b7", + "sha256:bbc6989fad0c030bd70a0b6f626f98a862224bc2b1e36bfc531ea2facc0a340c", + "sha256:be51dd2c8596b25fe43c0a4a59c2bee4f18d88efb8031188f9e7ddc6b469cf44", + "sha256:c365ad9c394f9eeffcb30a82f4246c0006417f03a7c0f8315d6211f25f7cb654", + "sha256:c3d5731a120752248844676bf92f25a12f6e45425e63ce22e0849297a093b5b0", + "sha256:ca832e124eda231a60a041da4f013e3ff24949d94a01154b137fc2f2a43c3ffb", + "sha256:d207d5b87f6cbefbdb1198154292faee8017d7495a54ae58db06762004500d00", + "sha256:d31ee5b14a82c9afe2bd26aaa405293d4237d0591527d9129ce36e58f19f95c1", + "sha256:d3b5c4cbd0c9cb61bbbb19ce335e1f8ab87a811f6d589ed52b0254cf585d709c", + "sha256:d573082c6ef99336f2cb5b667b781d2f776d4af311574fb53d908517ba523c22", + "sha256:e49db944fad339b2ccb80128ffd3f8af076f9f287197a480bf1e4ca053a866f0" + ], + "markers": "python_version >= '3.7'", + "version": "==1.10.15" + }, + "pydocstyle": { + "hashes": [ + "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019", + "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1" + ], + "markers": "python_version >= '3.6'", + "version": "==6.3.0" + }, + "pyflakes": { + "hashes": [ + "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f", + "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a" + ], + "markers": "python_version >= '3.8'", + "version": "==3.2.0" + }, + "pyrsistent": { + "hashes": [ + "sha256:0724c506cd8b63c69c7f883cc233aac948c1ea946ea95996ad8b1380c25e1d3f", + "sha256:09848306523a3aba463c4b49493a760e7a6ca52e4826aa100ee99d8d39b7ad1e", + "sha256:0f3b1bcaa1f0629c978b355a7c37acd58907390149b7311b5db1b37648eb6958", + "sha256:21cc459636983764e692b9eba7144cdd54fdec23ccdb1e8ba392a63666c60c34", + "sha256:2e14c95c16211d166f59c6611533d0dacce2e25de0f76e4c140fde250997b3ca", + "sha256:2e2c116cc804d9b09ce9814d17df5edf1df0c624aba3b43bc1ad90411487036d", + "sha256:4021a7f963d88ccd15b523787d18ed5e5269ce57aa4037146a2377ff607ae87d", + "sha256:4c48f78f62ab596c679086084d0dd13254ae4f3d6c72a83ffdf5ebdef8f265a4", + "sha256:4f5c2d012671b7391803263419e31b5c7c21e7c95c8760d7fc35602353dee714", + "sha256:58b8f6366e152092194ae68fefe18b9f0b4f89227dfd86a07770c3d86097aebf", + "sha256:59a89bccd615551391f3237e00006a26bcf98a4d18623a19909a2c48b8e986ee", + "sha256:5cdd7ef1ea7a491ae70d826b6cc64868de09a1d5ff9ef8d574250d0940e275b8", + "sha256:6288b3fa6622ad8a91e6eb759cfc48ff3089e7c17fb1d4c59a919769314af224", + "sha256:6d270ec9dd33cdb13f4d62c95c1a5a50e6b7cdd86302b494217137f760495b9d", + "sha256:79ed12ba79935adaac1664fd7e0e585a22caa539dfc9b7c7c6d5ebf91fb89054", + "sha256:7d29c23bdf6e5438c755b941cef867ec2a4a172ceb9f50553b6ed70d50dfd656", + "sha256:8441cf9616d642c475684d6cf2520dd24812e996ba9af15e606df5f6fd9d04a7", + "sha256:881bbea27bbd32d37eb24dd320a5e745a2a5b092a17f6debc1349252fac85423", + "sha256:8c3aba3e01235221e5b229a6c05f585f344734bd1ad42a8ac51493d74722bbce", + "sha256:a14798c3005ec892bbada26485c2eea3b54109cb2533713e355c806891f63c5e", + "sha256:b14decb628fac50db5e02ee5a35a9c0772d20277824cfe845c8a8b717c15daa3", + "sha256:b318ca24db0f0518630e8b6f3831e9cba78f099ed5c1d65ffe3e023003043ba0", + "sha256:c1beb78af5423b879edaf23c5591ff292cf7c33979734c99aa66d5914ead880f", + "sha256:c55acc4733aad6560a7f5f818466631f07efc001fd023f34a6c203f8b6df0f0b", + "sha256:ca52d1ceae015859d16aded12584c59eb3825f7b50c6cfd621d4231a6cc624ce", + "sha256:cae40a9e3ce178415040a0383f00e8d68b569e97f31928a3a8ad37e3fde6df6a", + "sha256:e78d0c7c1e99a4a45c99143900ea0546025e41bb59ebc10182e947cf1ece9174", + "sha256:ef3992833fbd686ee783590639f4b8343a57f1f75de8633749d984dc0eb16c86", + "sha256:f058a615031eea4ef94ead6456f5ec2026c19fb5bd6bfe86e9665c4158cf802f", + "sha256:f5ac696f02b3fc01a710427585c855f65cd9c640e14f52abe52020722bb4906b", + "sha256:f920385a11207dc372a028b3f1e1038bb244b3ec38d448e6d8e43c6b3ba20e98", + "sha256:fed2c3216a605dc9a6ea50c7e84c82906e3684c4e80d2908208f662a6cbf9022" + ], + "markers": "python_version >= '3.8'", + "version": "==0.20.0" + }, + "pytest": { + "hashes": [ + "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac", + "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==7.4.3" + }, + "snowballstemmer": { + "hashes": [ + "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", + "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a" + ], + "version": "==2.2.0" + }, + "sortedcontainers": { + "hashes": [ + "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", + "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0" + ], + "version": "==2.4.0" + }, + "test-data-generation": { + "editable": true, + "file": "." + }, + "tomli": { + "hashes": [ + "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", + "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" + ], + "markers": "python_version < '3.11'", + "version": "==2.0.1" + }, + "typing-extensions": { + "hashes": [ + "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0", + "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a" + ], + "markers": "python_version < '3.11'", + "version": "==4.11.0" + } + }, + "develop": {} +} diff --git a/test-data-generation/mypy.ini b/test-data-generation/mypy.ini new file mode 100644 index 00000000000..b94476cbcaa --- /dev/null +++ b/test-data-generation/mypy.ini @@ -0,0 +1,5 @@ +[mypy] +show_error_codes = True +warn_unused_configs = True +strict = True +exclude = setup.py \ No newline at end of file diff --git a/test-data-generation/pytest.ini b/test-data-generation/pytest.ini new file mode 100644 index 00000000000..49f04412746 --- /dev/null +++ b/test-data-generation/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +addopts = --color=yes --strict-markers +asyncio_mode = auto diff --git a/test-data-generation/setup.py b/test-data-generation/setup.py new file mode 100755 index 00000000000..4246340dd68 --- /dev/null +++ b/test-data-generation/setup.py @@ -0,0 +1,91 @@ +# Inspired by: +# https://hynek.me/articles/sharing-your-labor-of-love-pypi-quick-and-dirty/ +import sys +import codecs +import os +import os.path +from setuptools import setup, find_packages + +# make stdout blocking since Travis sets it to nonblocking +if os.name == "posix": + import fcntl + + flags = fcntl.fcntl(sys.stdout, fcntl.F_GETFL) + fcntl.fcntl(sys.stdout, fcntl.F_SETFL, flags & ~os.O_NONBLOCK) + +HERE = os.path.abspath(os.path.dirname(__file__)) +sys.path.append(os.path.join(HERE, "..", "scripts")) + +from python_build_utils import normalize_version # noqa: E402 + + +def get_version(): + buildno = os.getenv("BUILD_NUMBER") + project = os.getenv("OPENTRONS_PROJECT", "robot-stack") + git_dir = os.getenv("OPENTRONS_GIT_DIR", None) + if buildno: + normalize_opts = {"extra_tag": buildno} + else: + normalize_opts = {} + return normalize_version( + "test-data-generation", project, git_dir=git_dir, **normalize_opts + ) + + +VERSION = get_version() + +DISTNAME = "test_data_generation" +LICENSE = "Apache 2.0" +AUTHOR = "Opentrons" +EMAIL = "engineering@opentrons.com" +URL = "https://github.com/Opentrons/opentrons" +DOWNLOAD_URL = "" +CLASSIFIERS = [ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Operating System :: OS Independent", + "Intended Audience :: Science/Research", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Topic :: Scientific/Engineering", +] +KEYWORDS = ["robots", "protocols", "synbio", "pcr", "automation", "lab"] +DESCRIPTION = "Library for working with test data on the Opentrons robots" +PACKAGES = find_packages(where="src", exclude=["tests.*", "tests"]) +INSTALL_REQUIRES = [ + f"opentrons-shared-data=={VERSION}", +] + + +def read(*parts): + """ + Build an absolute path from *parts* and and return the contents of the + resulting file. Assume UTF-8 encoding. + """ + with codecs.open(os.path.join(HERE, *parts), "rb", "utf-8") as f: + return f.read() + + +if __name__ == "__main__": + setup( + python_requires="~=3.10", + name=DISTNAME, + description=DESCRIPTION, + license=LICENSE, + url=URL, + version=VERSION, + author=AUTHOR, + author_email=EMAIL, + maintainer=AUTHOR, + maintainer_email=EMAIL, + keywords=KEYWORDS, + long_description=__doc__, + packages=PACKAGES, + zip_safe=False, + classifiers=CLASSIFIERS, + install_requires=INSTALL_REQUIRES, + include_package_data=True, + package_dir={"": "src"}, + package_data={"test-data-generation": ["py.typed"]}, + ) diff --git a/test-data-generation/src/test_data_generation/__init__.py b/test-data-generation/src/test_data_generation/__init__.py new file mode 100644 index 00000000000..45f2dcce037 --- /dev/null +++ b/test-data-generation/src/test_data_generation/__init__.py @@ -0,0 +1 @@ +"""Test data generation.""" diff --git a/test-data-generation/src/test_data_generation/deck_configuration/__init__.py b/test-data-generation/src/test_data_generation/deck_configuration/__init__.py new file mode 100644 index 00000000000..616f424694c --- /dev/null +++ b/test-data-generation/src/test_data_generation/deck_configuration/__init__.py @@ -0,0 +1 @@ +"""Test data generation for deck configuration tests.""" diff --git a/test-data-generation/src/test_data_generation/deck_configuration/datashapes.py b/test-data-generation/src/test_data_generation/deck_configuration/datashapes.py new file mode 100644 index 00000000000..94cf907e308 --- /dev/null +++ b/test-data-generation/src/test_data_generation/deck_configuration/datashapes.py @@ -0,0 +1,299 @@ +"""Data shapes for the deck configuration of a Flex.""" + +import enum +import dataclasses +import typing + +ColumnName = typing.Literal["1", "2", "3"] +RowName = typing.Literal["a", "b", "c", "d"] +SlotName = typing.Literal[ + "a1", "a2", "a3", "b1", "b2", "b3", "c1", "c2", "c3", "d1", "d2", "d3" +] + + +class PossibleSlotContents(enum.Enum): + """Possible contents of a slot on a Flex.""" + + # Implicitly defined fixtures + THERMOCYCLER_MODULE = enum.auto() + WASTE_CHUTE = enum.auto() + WASTE_CHUTE_NO_COVER = enum.auto() + STAGING_AREA = enum.auto() + STAGING_AREA_WITH_WASTE_CHUTE = enum.auto() + STAGING_AREA_WITH_WASTE_CHUTE_NO_COVER = enum.auto() + STAGING_AREA_WITH_MAGNETIC_BLOCK = enum.auto() + + # Explicitly defined fixtures + MAGNETIC_BLOCK_MODULE = enum.auto() + TEMPERATURE_MODULE = enum.auto() + HEATER_SHAKER_MODULE = enum.auto() + TRASH_BIN = enum.auto() + + # Other + LABWARE_SLOT = enum.auto() + + @classmethod + def longest_string(cls) -> int: + """Return the longest string representation of the slot content.""" + length = max([len(e.name) for e in PossibleSlotContents]) + return length if length % 2 == 0 else length + 1 + + def __str__(self) -> str: + """Return a string representation of the slot content.""" + return f"{self.name.replace('_', ' ')}" + + @classmethod + def all(cls) -> typing.List["PossibleSlotContents"]: + """Return all possible slot contents.""" + return list(cls) + + @property + def modules(self) -> typing.List["PossibleSlotContents"]: + """Return the modules.""" + return [ + PossibleSlotContents.THERMOCYCLER_MODULE, + PossibleSlotContents.MAGNETIC_BLOCK_MODULE, + PossibleSlotContents.TEMPERATURE_MODULE, + PossibleSlotContents.HEATER_SHAKER_MODULE, + ] + + @property + def staging_areas(self) -> typing.List["PossibleSlotContents"]: + """Return the staging areas.""" + return [ + PossibleSlotContents.STAGING_AREA, + PossibleSlotContents.STAGING_AREA_WITH_WASTE_CHUTE, + PossibleSlotContents.STAGING_AREA_WITH_WASTE_CHUTE_NO_COVER, + PossibleSlotContents.STAGING_AREA_WITH_MAGNETIC_BLOCK, + ] + + @property + def waste_chutes(self) -> typing.List["PossibleSlotContents"]: + """Return the waste chutes.""" + return [ + PossibleSlotContents.WASTE_CHUTE, + PossibleSlotContents.WASTE_CHUTE_NO_COVER, + PossibleSlotContents.STAGING_AREA_WITH_WASTE_CHUTE, + PossibleSlotContents.STAGING_AREA_WITH_WASTE_CHUTE_NO_COVER, + ] + + def is_one_of(self, contents: typing.List["PossibleSlotContents"]) -> bool: + """Return True if the slot contains one of the contents.""" + return any([self is content for content in contents]) + + def is_a_module(self) -> bool: + """Return True if the slot contains a module.""" + return self.is_one_of(self.modules) + + def is_module_or_trash_bin(self) -> bool: + """Return True if the slot contains a module or trash bin.""" + return self.is_one_of(self.modules + [PossibleSlotContents.TRASH_BIN]) + + def is_a_staging_area(self) -> bool: + """Return True if the slot contains a staging area.""" + return self.is_one_of(self.staging_areas) + + def is_a_waste_chute(self) -> bool: + """Return True if the slot contains a waste chute.""" + return self.is_one_of(self.waste_chutes) + + +@dataclasses.dataclass +class Slot: + """A slot on a Flex.""" + + row: RowName + col: ColumnName + contents: PossibleSlotContents + + def __str__(self) -> str: + """Return a string representation of the slot.""" + return f"{(self.row + self.col).center(self.contents.longest_string())}{self.contents}" + + @property + def __label(self) -> SlotName: + """Return the slot label.""" + return typing.cast(SlotName, f"{self.row}{self.col}") + + @property + def slot_label_string(self) -> str: + """Return the slot label.""" + return f"{self.__label.center(self.contents.longest_string())}" + + @property + def contents_string(self) -> str: + """Return the slot contents.""" + return f"{str(self.contents).center(self.contents.longest_string())}" + + +@dataclasses.dataclass +class Row: + """A row of slots on a Flex.""" + + row: RowName + + col1: Slot + col2: Slot + col3: Slot + + def __str__(self) -> str: + """Return a string representation of the row.""" + return f"{self.col1}{self.col2}{self.col3}" + + def slot_by_col_number(self, name: ColumnName) -> Slot: + """Return the slot by name.""" + return getattr(self, f"col{name}") # type: ignore + + @property + def slots(self) -> typing.List[Slot]: + """Iterate over the slots in the row.""" + return [self.col1, self.col2, self.col3] + + def __len__(self) -> int: + """Return the number of slots in the row.""" + return len(self.slots) + + def update_slot(self, slot: Slot) -> None: + """Update the slot in the row.""" + setattr(self, f"col{slot.col}", slot) + + +@dataclasses.dataclass +class Column: + """A column of slots on a Flex.""" + + col: ColumnName + + a: Slot + b: Slot + c: Slot + d: Slot + + def __str__(self) -> str: + """Return a string representation of the column.""" + return f"{self.a}{self.b}{self.c}{self.d}" + + @property + def slots(self) -> typing.List[Slot]: + """Return the slots in the column.""" + return [self.a, self.b, self.c, self.d] + + def slot_by_row(self, name: RowName) -> Slot: + """Return the slot by name.""" + return getattr(self, f"{name}") # type: ignore + + def number_of(self, contents: PossibleSlotContents) -> int: + """Return the number of slots with the contents.""" + return len([True for slot in self.slots if slot.contents is contents]) + + def slot_above(self, slot: Slot) -> typing.Optional[Slot]: + """Return the slot above the passed slot.""" + index = self.slots.index(slot) + if index == 0: + return None + return self.slots[index - 1] + + def slot_below(self, slot: Slot) -> typing.Optional[Slot]: + """Return the slot below the passed slot.""" + index = self.slots.index(slot) + if index == 3: + return None + return self.slots[index + 1] + + +@dataclasses.dataclass +class DeckConfiguration: + """The deck on a Flex.""" + + a: Row + b: Row + c: Row + d: Row + + def __str__(self) -> str: + """Return a string representation of the deck.""" + string_list = [] + dashed_line = "-" * (PossibleSlotContents.longest_string() * 3) + equal_line = "=" * (PossibleSlotContents.longest_string() * 3) + for row in self.rows: + string_list.append( + " | ".join([slot.slot_label_string for slot in row.slots]) + ) + string_list.append(" | ".join([slot.contents_string for slot in row.slots])) + if row != self.d: + string_list.append(dashed_line) + joined_string = "\n".join(string_list) + + return f"\n{joined_string}\n\n{equal_line}" + + def __hash__(self) -> int: + """Return the hash of the deck.""" + return hash(tuple(slot.contents.value for slot in self.slots)) + + def __eq__(self, other: typing.Any) -> bool: + """Return True if the deck is equal to the other deck.""" + if not isinstance(other, DeckConfiguration): + return False + return all( + slot.contents == other_slot.contents + for slot in self.slots + for other_slot in other.slots + ) + + @classmethod + def from_cols(cls, col1: Column, col2: Column, col3: Column) -> "DeckConfiguration": + """Create a deck configuration from columns.""" + return cls( + a=Row("a", col1.a, col2.a, col3.a), + b=Row("b", col1.b, col2.b, col3.b), + c=Row("c", col1.c, col2.c, col3.c), + d=Row("d", col1.d, col2.d, col3.d), + ) + + @property + def rows(self) -> typing.List[Row]: + """Return the rows of the deck.""" + return [self.a, self.b, self.c, self.d] + + def row_by_name(self, name: RowName) -> Row: + """Return the row by name.""" + return getattr(self, name) # type: ignore + + @property + def slots(self) -> typing.List[Slot]: + """Return the slots of the deck.""" + return [slot for row in self.rows for slot in row.slots] + + def slot_above(self, slot: Slot) -> typing.Optional[Slot]: + """Return the slot above the passed slot.""" + row_index = self.rows.index(self.row_by_name(slot.row)) + if row_index == 0: + return None + return self.rows[row_index - 1].slot_by_col_number(slot.col) + + def slot_below(self, slot: Slot) -> typing.Optional[Slot]: + """Return the slot below the passed slot.""" + row_index = self.rows.index(self.row_by_name(slot.row)) + if row_index == 3: + return None + return self.rows[row_index + 1].slot_by_col_number(slot.col) + + def number_of(self, contents: PossibleSlotContents) -> int: + """Return the number of slots with the contents.""" + return len([True for slot in self.slots if slot.contents is contents]) + + def override_with_column(self, column: Column) -> None: + """Override the deck configuration with the column.""" + for row in self.rows: + new_value = column.slot_by_row(row.row) + row.update_slot(new_value) + + def column_by_number(self, number: ColumnName) -> Column: + """Return the column by number.""" + return Column( + col=number, + a=self.a.slot_by_col_number(number), + b=self.b.slot_by_col_number(number), + c=self.c.slot_by_col_number(number), + d=self.d.slot_by_col_number(number), + ) diff --git a/test-data-generation/src/test_data_generation/deck_configuration/strategy/final_strategies.py b/test-data-generation/src/test_data_generation/deck_configuration/strategy/final_strategies.py new file mode 100644 index 00000000000..9bf70180f96 --- /dev/null +++ b/test-data-generation/src/test_data_generation/deck_configuration/strategy/final_strategies.py @@ -0,0 +1,81 @@ +"""Test data generation for deck configuration tests.""" +from hypothesis import assume, strategies as st +from test_data_generation.deck_configuration.datashapes import ( + Column, + DeckConfiguration, + Slot, + PossibleSlotContents as PSC, +) + +from test_data_generation.deck_configuration.strategy.helper_strategies import a_column + + +def _above_or_below_is_module_or_trash(col: Column, slot: Slot) -> bool: + """Return True if the deck has a module above or below the specified slot.""" + above = col.slot_above(slot) + below = col.slot_below(slot) + + return (above is not None and above.contents.is_module_or_trash_bin()) or ( + below is not None and below.contents.is_module_or_trash_bin() + ) + + +@st.composite +def a_deck_configuration_with_a_module_or_trash_slot_above_or_below_a_heater_shaker( + draw: st.DrawFn, +) -> DeckConfiguration: + """Generate a deck with a module or trash bin fixture above or below a heater shaker.""" + deck = draw( + st.builds( + DeckConfiguration.from_cols, + col1=a_column("1"), + col2=a_column( + "2", content_options=[PSC.LABWARE_SLOT, PSC.MAGNETIC_BLOCK_MODULE] + ), + col3=a_column("3"), + ) + ) + column = deck.column_by_number(draw(st.sampled_from(["1", "3"]))) + + assume(column.number_of(PSC.HEATER_SHAKER_MODULE) in [1, 2]) + for slot in column.slots: + if slot.contents is PSC.HEATER_SHAKER_MODULE: + assume(_above_or_below_is_module_or_trash(column, slot)) + deck.override_with_column(column) + + return deck + + +@st.composite +def a_deck_configuration_with_invalid_fixture_in_col_2( + draw: st.DrawFn, +) -> DeckConfiguration: + """Generate a deck with an invalid fixture in column 2.""" + POSSIBLE_FIXTURES = [ + PSC.LABWARE_SLOT, + PSC.TEMPERATURE_MODULE, + PSC.HEATER_SHAKER_MODULE, + PSC.TRASH_BIN, + PSC.MAGNETIC_BLOCK_MODULE, + ] + INVALID_FIXTURES = [ + PSC.HEATER_SHAKER_MODULE, + PSC.TRASH_BIN, + PSC.TEMPERATURE_MODULE, + ] + column2 = draw(a_column("2", content_options=POSSIBLE_FIXTURES)) + num_invalid_fixtures = len( + [True for slot in column2.slots if slot.contents.is_one_of(INVALID_FIXTURES)] + ) + assume(num_invalid_fixtures > 0) + + deck = draw( + st.builds( + DeckConfiguration.from_cols, + col1=a_column("1"), + col2=st.just(column2), + col3=a_column("3"), + ) + ) + + return deck diff --git a/test-data-generation/src/test_data_generation/deck_configuration/strategy/helper_strategies.py b/test-data-generation/src/test_data_generation/deck_configuration/strategy/helper_strategies.py new file mode 100644 index 00000000000..17950f63a39 --- /dev/null +++ b/test-data-generation/src/test_data_generation/deck_configuration/strategy/helper_strategies.py @@ -0,0 +1,117 @@ +"""Test data generation for deck configuration tests.""" +from typing import List +from hypothesis import strategies as st +from test_data_generation.deck_configuration.datashapes import ( + Column, + Row, + Slot, + PossibleSlotContents as PSC, +) + + +@st.composite +def a_slot( + draw: st.DrawFn, + row: str, + col: str, + content_options: List[PSC] = PSC.all(), +) -> Slot: + """Generate a slot with a random content. + + Any fixture that has it's location implicitly defined is captured here by the + filtering logic. + """ + no_thermocycler = [ + content for content in content_options if content is not PSC.THERMOCYCLER_MODULE + ] + no_waste_chute_or_staging_area = [ + content + for content in content_options + if not content.is_a_waste_chute() and not content.is_a_staging_area() + ] + + no_waste_chute_or_thermocycler = [ + content for content in no_thermocycler if not content.is_a_waste_chute() + ] + no_staging_area_or_waste_chute_or_thermocycler = [ + content + for content in no_waste_chute_or_thermocycler + if not content.is_a_staging_area() + ] + + if col == "1" and (row == "A" or row == "B"): + return draw( + st.builds( + Slot, + row=st.just(row), + col=st.just(col), + contents=st.sampled_from(no_waste_chute_or_staging_area), + ) + ) + elif col == "3": + if row == "D": + return draw( + st.builds( + Slot, + row=st.just(row), + col=st.just(col), + contents=st.sampled_from(no_thermocycler), + ) + ) + else: + return draw( + st.builds( + Slot, + row=st.just(row), + col=st.just(col), + contents=st.sampled_from(no_waste_chute_or_thermocycler), + ) + ) + else: + return draw( + st.builds( + Slot, + row=st.just(row), + col=st.just(col), + contents=st.sampled_from( + no_staging_area_or_waste_chute_or_thermocycler + ), + ) + ) + + +@st.composite +def a_row( + draw: st.DrawFn, + row: str, + content_options: List[PSC] = PSC.all(), +) -> Row: + """Generate a row with random slots.""" + return draw( + st.builds( + Row, + row=st.just(row), + col1=a_slot(row=row, col="1", content_options=content_options), + col2=a_slot(row=row, col="2", content_options=content_options), + col3=a_slot(row=row, col="3", content_options=content_options), + ) + ) + + +@st.composite +def a_column( + draw: st.DrawFn, + col: str, + content_options: List[PSC] = PSC.all(), +) -> Column: + """Generate a column with random slots.""" + return draw( + st.builds( + Column, + col=st.just(col), + a=a_slot(row="a", col=col, content_options=content_options), + b=a_slot(row="b", col=col, content_options=content_options), + c=a_slot(row="c", col=col, content_options=content_options), + d=a_slot(row="d", col=col, content_options=content_options), + ) + ) diff --git a/test-data-generation/tests/test_data_generation/deck_configuration/test_deck_configuration.py b/test-data-generation/tests/test_data_generation/deck_configuration/test_deck_configuration.py new file mode 100644 index 00000000000..02c4f125187 --- /dev/null +++ b/test-data-generation/tests/test_data_generation/deck_configuration/test_deck_configuration.py @@ -0,0 +1,41 @@ +"""Tests to ensure that the deck configuration is generated correctly.""" + +from hypothesis import given, settings, HealthCheck +from test_data_generation.deck_configuration.datashapes import DeckConfiguration +from test_data_generation.deck_configuration.strategy.final_strategies import ( + a_deck_configuration_with_a_module_or_trash_slot_above_or_below_a_heater_shaker, + a_deck_configuration_with_invalid_fixture_in_col_2, +) + +NUM_EXAMPLES = 100 + + +@given( + deck_config=a_deck_configuration_with_a_module_or_trash_slot_above_or_below_a_heater_shaker() +) +@settings( + max_examples=NUM_EXAMPLES, + suppress_health_check=[HealthCheck.filter_too_much, HealthCheck.too_slow], +) +def test_above_below_heater_shaker(deck_config: DeckConfiguration) -> None: + """I hypothesize, that any deck configuration with a non-labware slot fixture above or below a heater-shaker is invalid.""" + print(deck_config) + + # TODO: create protocol and run analysis + + # protocol = create_protocol(deck) + # with pytest.assertRaises as e: + # analyze(protocol) + # assert e.exception == "Some statement about the deck configuration being invalid because of the labware above or below the Heater-Shaker" + + +@given(deck_config=a_deck_configuration_with_invalid_fixture_in_col_2()) +@settings( + max_examples=NUM_EXAMPLES, + suppress_health_check=[HealthCheck.filter_too_much, HealthCheck.too_slow], +) +def test_invalid_fixture_in_col_2(deck_config: DeckConfiguration) -> None: + """I hypothesize, that any deck configuration that contains at least one, Heater-Shaker, Trash Bin, or Temperature module, in column 2 is invalid.""" + print(deck_config) + + # TODO: Same as above diff --git a/tsconfig-eslint.json b/tsconfig-eslint.json index 4468d4f6fd4..541feb786c0 100644 --- a/tsconfig-eslint.json +++ b/tsconfig-eslint.json @@ -19,6 +19,7 @@ "labware-designer/typings", "labware-library/src", "labware-library/typings", + "opentrons-ai-client/src", "shared-data/deck", "shared-data/js", "shared-data/protocol", diff --git a/usb-bridge/node-client/webpack.config.js b/usb-bridge/node-client/webpack.config.js deleted file mode 100644 index c01e57beb07..00000000000 --- a/usb-bridge/node-client/webpack.config.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict' - -const path = require('path') -const webpackMerge = require('webpack-merge') -const { DefinePlugin } = require('webpack') -const { nodeBaseConfig } = require('@opentrons/webpack-config') -const { versionForProject } = require('../../scripts/git-version') - -const ENTRY_INDEX = path.join(__dirname, 'src/index.ts') -const ENTRY_CLI = path.join(__dirname, 'src/cli.ts') -const OUTPUT_PATH = path.join(__dirname, 'lib') -const project = process.env.OPENTRONS_PROJECT ?? 'robot-stack' - -module.exports = async () => - webpackMerge(nodeBaseConfig, { - entry: { - index: ENTRY_INDEX, - cli: ENTRY_CLI, - }, - output: { path: OUTPUT_PATH }, - plugins: [ - new DefinePlugin({ - _PKG_VERSION_: JSON.stringify(await versionForProject(project)), - }), - ], - }) diff --git a/yarn.lock b/yarn.lock index 9773a4fe6f3..8427f656e8d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -37,33 +37,33 @@ dependencies: default-browser-id "3.0.0" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" - integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.1", "@babel/code-frame@^7.24.2": + version "7.24.2" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae" + integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== dependencies: - "@babel/highlight" "^7.23.4" - chalk "^2.4.2" + "@babel/highlight" "^7.24.2" + picocolors "^1.0.0" -"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.5.tgz#ffb878728bb6bdcb6f4510aa51b1be9afb8cfd98" - integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw== +"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.23.5", "@babel/compat-data@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.4.tgz#6f102372e9094f25d908ca0d34fc74c74606059a" + integrity sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ== "@babel/core@>=7.2.2", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.18.9", "@babel/core@^7.20.12", "@babel/core@^7.23.0", "@babel/core@^7.23.2", "@babel/core@^7.23.3", "@babel/core@^7.23.5": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.0.tgz#56cbda6b185ae9d9bed369816a8f4423c5f2ff1b" - integrity sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw== + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.4.tgz#1f758428e88e0d8c563874741bc4ffc4f71a4717" + integrity sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.23.5" - "@babel/generator" "^7.23.6" + "@babel/code-frame" "^7.24.2" + "@babel/generator" "^7.24.4" "@babel/helper-compilation-targets" "^7.23.6" "@babel/helper-module-transforms" "^7.23.3" - "@babel/helpers" "^7.24.0" - "@babel/parser" "^7.24.0" + "@babel/helpers" "^7.24.4" + "@babel/parser" "^7.24.4" "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.0" + "@babel/traverse" "^7.24.1" "@babel/types" "^7.24.0" convert-source-map "^2.0.0" debug "^4.1.0" @@ -71,14 +71,14 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.23.0", "@babel/generator@^7.23.6": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e" - integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw== +"@babel/generator@^7.23.0", "@babel/generator@^7.24.1", "@babel/generator@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.4.tgz#1fc55532b88adf952025d5d2d1e71f946cb1c498" + integrity sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw== dependencies: - "@babel/types" "^7.23.6" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" + "@babel/types" "^7.24.0" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" "@babel/helper-annotate-as-pure@^7.16.0", "@babel/helper-annotate-as-pure@^7.22.5": @@ -95,7 +95,7 @@ dependencies: "@babel/types" "^7.22.15" -"@babel/helper-compilation-targets@^7.22.15", "@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.23.6": +"@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.23.6": version "7.23.6" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz#4d79069b16cbcf1461289eccfbbd81501ae39991" integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== @@ -106,17 +106,17 @@ lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-create-class-features-plugin@^7.22.15", "@babel/helper-create-class-features-plugin@^7.23.6": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.0.tgz#fc7554141bdbfa2d17f7b4b80153b9b090e5d158" - integrity sha512-QAH+vfvts51BCsNZ2PhY6HAggnlS6omLLFTsIpeqZk/MmJ6cW7tgz5yRv0fMJThcr6FmbMrENh1RgrWPTYA76g== +"@babel/helper-create-class-features-plugin@^7.24.1", "@babel/helper-create-class-features-plugin@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz#c806f73788a6800a5cfbbc04d2df7ee4d927cce3" + integrity sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ== dependencies: "@babel/helper-annotate-as-pure" "^7.22.5" "@babel/helper-environment-visitor" "^7.22.20" "@babel/helper-function-name" "^7.23.0" "@babel/helper-member-expression-to-functions" "^7.23.0" "@babel/helper-optimise-call-expression" "^7.22.5" - "@babel/helper-replace-supers" "^7.22.20" + "@babel/helper-replace-supers" "^7.24.1" "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" "@babel/helper-split-export-declaration" "^7.22.6" semver "^6.3.1" @@ -130,10 +130,10 @@ regexpu-core "^5.3.1" semver "^6.3.1" -"@babel/helper-define-polyfill-provider@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz#465805b7361f461e86c680f1de21eaf88c25901b" - integrity sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q== +"@babel/helper-define-polyfill-provider@^0.6.1", "@babel/helper-define-polyfill-provider@^0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz#18594f789c3594acb24cfdb4a7f7b7d2e8bd912d" + integrity sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ== dependencies: "@babel/helper-compilation-targets" "^7.22.6" "@babel/helper-plugin-utils" "^7.22.5" @@ -161,19 +161,19 @@ dependencies: "@babel/types" "^7.22.5" -"@babel/helper-member-expression-to-functions@^7.22.15", "@babel/helper-member-expression-to-functions@^7.23.0": +"@babel/helper-member-expression-to-functions@^7.23.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz#9263e88cc5e41d39ec18c9a3e0eced59a3e7d366" integrity sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA== dependencies: "@babel/types" "^7.23.0" -"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.16.0", "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.22.15", "@babel/helper-module-imports@^7.22.5": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" - integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== +"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.16.0", "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.22.15", "@babel/helper-module-imports@^7.22.5", "@babel/helper-module-imports@^7.24.1": + version "7.24.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz#6ac476e6d168c7c23ff3ba3cf4f7841d46ac8128" + integrity sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg== dependencies: - "@babel/types" "^7.22.15" + "@babel/types" "^7.24.0" "@babel/helper-module-transforms@^7.23.3": version "7.23.3" @@ -207,13 +207,13 @@ "@babel/helper-environment-visitor" "^7.22.20" "@babel/helper-wrap-function" "^7.22.20" -"@babel/helper-replace-supers@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz#e37d367123ca98fe455a9887734ed2e16eb7a793" - integrity sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw== +"@babel/helper-replace-supers@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz#7085bd19d4a0b7ed8f405c1ed73ccb70f323abc1" + integrity sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ== dependencies: "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-member-expression-to-functions" "^7.22.15" + "@babel/helper-member-expression-to-functions" "^7.23.0" "@babel/helper-optimise-call-expression" "^7.22.5" "@babel/helper-simple-access@^7.22.5": @@ -238,16 +238,16 @@ "@babel/types" "^7.22.5" "@babel/helper-string-parser@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" - integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz#f99c36d3593db9540705d0739a1f10b5e20c696e" + integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== "@babel/helper-validator-identifier@^7.22.20": version "7.22.20" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== -"@babel/helper-validator-option@^7.22.15", "@babel/helper-validator-option@^7.23.5": +"@babel/helper-validator-option@^7.23.5": version "7.23.5" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== @@ -261,52 +261,61 @@ "@babel/template" "^7.22.15" "@babel/types" "^7.22.19" -"@babel/helpers@^7.24.0": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.0.tgz#a3dd462b41769c95db8091e49cfe019389a9409b" - integrity sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA== +"@babel/helpers@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.4.tgz#dc00907fd0d95da74563c142ef4cd21f2cb856b6" + integrity sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw== dependencies: "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.0" + "@babel/traverse" "^7.24.1" "@babel/types" "^7.24.0" -"@babel/highlight@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" - integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== +"@babel/highlight@^7.24.2": + version "7.24.2" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.2.tgz#3f539503efc83d3c59080a10e6634306e0370d26" + integrity sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA== dependencies: "@babel/helper-validator-identifier" "^7.22.20" chalk "^2.4.2" js-tokens "^4.0.0" + picocolors "^1.0.0" -"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.0", "@babel/parser@^7.23.6", "@babel/parser@^7.24.0", "@babel/parser@^7.8.3": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.0.tgz#26a3d1ff49031c53a97d03b604375f028746a9ac" - integrity sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg== +"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.0", "@babel/parser@^7.24.0", "@babel/parser@^7.24.1", "@babel/parser@^7.24.4", "@babel/parser@^7.8.3": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.4.tgz#234487a110d89ad5a3ed4a8a566c36b9453e8c88" + integrity sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg== -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz#5cd1c87ba9380d0afb78469292c954fee5d2411a" - integrity sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ== +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.4.tgz#6125f0158543fb4edf1c22f322f3db67f21cb3e1" + integrity sha512-qpl6vOOEEzTLLcsuqYYo8yDtrTocmu2xkGvgNebvPjT9DTtfFYGmgDqY+rBYXNlqL4s9qLDn6xkrJv4RxAPiTA== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz#f6652bb16b94f8f9c20c50941e16e9756898dc5d" - integrity sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ== +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.1.tgz#b645d9ba8c2bc5b7af50f0fe949f9edbeb07c8cf" + integrity sha512-y4HqEnkelJIOQGd+3g1bTeKsA5c6qM7eOn7VggGVbBc0y8MLSKHacwcIE2PplNlQSj0PqS9rrXL/nkPVK+kUNg== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.1.tgz#da8261f2697f0f41b0855b91d3a20a1fbfd271d3" + integrity sha512-Hj791Ii4ci8HqnaKHAlLNs+zaLXb0EzSDhiAWp5VNlyvCNymYfacs64pxTxbH1znW/NcArSmwpmG9IKE/TUVVQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" - "@babel/plugin-transform-optional-chaining" "^7.23.3" + "@babel/plugin-transform-optional-chaining" "^7.24.1" -"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.23.7": - version "7.23.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.7.tgz#516462a95d10a9618f197d39ad291a9b47ae1d7b" - integrity sha512-LlRT7HgaifEpQA1ZgLVOIJZZFVPWN5iReq/7/JixwBtwcoeVGDBD53ZV28rrsLYOZs1Y/EHhA8N/Z6aazHR8cw== +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.1.tgz#1181d9685984c91d657b8ddf14f0487a6bab2988" + integrity sha512-m9m/fXsXLiHfwdgydIFnpk+7jlVbnvlK5B2EKiPdLUb6WX654ZaaEWJUjk8TftRbZpK0XibovlLWX4KIZhV6jw== dependencies: "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": version "7.21.0-placeholder-for-preset-env.2" @@ -348,26 +357,26 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-syntax-flow@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.23.3.tgz#084564e0f3cc21ea6c70c44cff984a1c0509729a" - integrity sha512-YZiAIpkJAwQXBJLIQbRFayR5c+gJ35Vcz3bg954k7cd73zqjvhacJuL9RbrzPz8qPmZdgqP6EUKwy0PCNhaaPA== +"@babel/plugin-syntax-flow@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.24.1.tgz#875c25e3428d7896c87589765fc8b9d32f24bd8d" + integrity sha512-sxi2kLTI5DeW5vDtMUsk4mTPwvlUDbjOnoWayhynCwrw4QXRld4QEYwqzY8JmQXaJUtgUuCIurtSRH5sn4c7mA== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-syntax-import-assertions@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz#9c05a7f592982aff1a2768260ad84bcd3f0c77fc" - integrity sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw== +"@babel/plugin-syntax-import-assertions@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz#db3aad724153a00eaac115a3fb898de544e34971" + integrity sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-syntax-import-attributes@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.23.3.tgz#992aee922cf04512461d7dae3ff6951b90a2dc06" - integrity sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA== +"@babel/plugin-syntax-import-attributes@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.1.tgz#c66b966c63b714c4eec508fcf5763b1f2d381093" + integrity sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-syntax-import-meta@^7.10.4": version "7.10.4" @@ -383,12 +392,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-jsx@^7.22.5", "@babel/plugin-syntax-jsx@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz#8f2e4f8a9b5f9aa16067e142c1ac9cd9f810f473" - integrity sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg== +"@babel/plugin-syntax-jsx@^7.22.5", "@babel/plugin-syntax-jsx@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz#3f6ca04b8c841811dbc3c5c5f837934e0d626c10" + integrity sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" @@ -446,12 +455,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-typescript@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz#24f460c85dbbc983cd2b9c4994178bcc01df958f" - integrity sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ== +"@babel/plugin-syntax-typescript@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz#b3bcc51f396d15f3591683f90239de143c076844" + integrity sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-syntax-unicode-sets-regex@^7.18.6": version "7.18.6" @@ -461,220 +470,220 @@ "@babel/helper-create-regexp-features-plugin" "^7.18.6" "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-arrow-functions@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz#94c6dcfd731af90f27a79509f9ab7fb2120fc38b" - integrity sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ== +"@babel/plugin-transform-arrow-functions@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.1.tgz#2bf263617060c9cc45bcdbf492b8cc805082bf27" + integrity sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-async-generator-functions@^7.23.9": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.9.tgz#9adaeb66fc9634a586c5df139c6240d41ed801ce" - integrity sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ== +"@babel/plugin-transform-async-generator-functions@^7.24.3": + version "7.24.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.3.tgz#8fa7ae481b100768cc9842c8617808c5352b8b89" + integrity sha512-Qe26CMYVjpQxJ8zxM1340JFNjZaF+ISWpr1Kt/jGo+ZTUzKkfw/pphEWbRCb+lmSM6k/TOgfYLvmbHkUQ0asIg== dependencies: "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/helper-remap-async-to-generator" "^7.22.20" "@babel/plugin-syntax-async-generators" "^7.8.4" -"@babel/plugin-transform-async-to-generator@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz#d1f513c7a8a506d43f47df2bf25f9254b0b051fa" - integrity sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw== +"@babel/plugin-transform-async-to-generator@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.1.tgz#0e220703b89f2216800ce7b1c53cb0cf521c37f4" + integrity sha512-AawPptitRXp1y0n4ilKcGbRYWfbbzFWz2NqNu7dacYDtFtz0CMjG64b3LQsb3KIgnf4/obcUL78hfaOS7iCUfw== dependencies: - "@babel/helper-module-imports" "^7.22.15" - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-module-imports" "^7.24.1" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/helper-remap-async-to-generator" "^7.22.20" -"@babel/plugin-transform-block-scoped-functions@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz#fe1177d715fb569663095e04f3598525d98e8c77" - integrity sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A== +"@babel/plugin-transform-block-scoped-functions@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.1.tgz#1c94799e20fcd5c4d4589523bbc57b7692979380" + integrity sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-block-scoping@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz#b2d38589531c6c80fbe25e6b58e763622d2d3cf5" - integrity sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw== +"@babel/plugin-transform-block-scoping@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.4.tgz#28f5c010b66fbb8ccdeef853bef1935c434d7012" + integrity sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-class-properties@^7.22.5", "@babel/plugin-transform-class-properties@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz#35c377db11ca92a785a718b6aa4e3ed1eb65dc48" - integrity sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg== +"@babel/plugin-transform-class-properties@^7.22.5", "@babel/plugin-transform-class-properties@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.1.tgz#bcbf1aef6ba6085cfddec9fc8d58871cf011fc29" + integrity sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g== dependencies: - "@babel/helper-create-class-features-plugin" "^7.22.15" - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-create-class-features-plugin" "^7.24.1" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-class-static-block@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.23.4.tgz#2a202c8787a8964dd11dfcedf994d36bfc844ab5" - integrity sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ== +"@babel/plugin-transform-class-static-block@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.4.tgz#1a4653c0cf8ac46441ec406dece6e9bc590356a4" + integrity sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg== dependencies: - "@babel/helper-create-class-features-plugin" "^7.22.15" - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-create-class-features-plugin" "^7.24.4" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-syntax-class-static-block" "^7.14.5" -"@babel/plugin-transform-classes@^7.23.8": - version "7.23.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.8.tgz#d08ae096c240347badd68cdf1b6d1624a6435d92" - integrity sha512-yAYslGsY1bX6Knmg46RjiCiNSwJKv2IUC8qOdYKqMMr0491SXFhcHqOdRDeCRohOOIzwN/90C6mQ9qAKgrP7dg== +"@babel/plugin-transform-classes@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.1.tgz#5bc8fc160ed96378184bc10042af47f50884dcb1" + integrity sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q== dependencies: "@babel/helper-annotate-as-pure" "^7.22.5" "@babel/helper-compilation-targets" "^7.23.6" "@babel/helper-environment-visitor" "^7.22.20" "@babel/helper-function-name" "^7.23.0" - "@babel/helper-plugin-utils" "^7.22.5" - "@babel/helper-replace-supers" "^7.22.20" + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-replace-supers" "^7.24.1" "@babel/helper-split-export-declaration" "^7.22.6" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz#652e69561fcc9d2b50ba4f7ac7f60dcf65e86474" - integrity sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw== +"@babel/plugin-transform-computed-properties@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz#bc7e787f8e021eccfb677af5f13c29a9934ed8a7" + integrity sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - "@babel/template" "^7.22.15" + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/template" "^7.24.0" -"@babel/plugin-transform-destructuring@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz#8c9ee68228b12ae3dff986e56ed1ba4f3c446311" - integrity sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw== +"@babel/plugin-transform-destructuring@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.1.tgz#b1e8243af4a0206841973786292b8c8dd8447345" + integrity sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-dotall-regex@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz#3f7af6054882ede89c378d0cf889b854a993da50" - integrity sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ== +"@babel/plugin-transform-dotall-regex@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.1.tgz#d56913d2f12795cc9930801b84c6f8c47513ac13" + integrity sha512-p7uUxgSoZwZ2lPNMzUkqCts3xlp8n+o05ikjy7gbtFJSt9gdU88jAmtfmOxHM14noQXBxfgzf2yRWECiNVhTCw== dependencies: "@babel/helper-create-regexp-features-plugin" "^7.22.15" - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-duplicate-keys@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz#664706ca0a5dfe8d066537f99032fc1dc8b720ce" - integrity sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA== +"@babel/plugin-transform-duplicate-keys@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.1.tgz#5347a797fe82b8d09749d10e9f5b83665adbca88" + integrity sha512-msyzuUnvsjsaSaocV6L7ErfNsa5nDWL1XKNnDePLgmz+WdU4w/J8+AxBMrWfi9m4IxfL5sZQKUPQKDQeeAT6lA== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-dynamic-import@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.23.4.tgz#c7629e7254011ac3630d47d7f34ddd40ca535143" - integrity sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ== +"@babel/plugin-transform-dynamic-import@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.1.tgz#2a5a49959201970dd09a5fca856cb651e44439dd" + integrity sha512-av2gdSTyXcJVdI+8aFZsCAtR29xJt0S5tas+Ef8NvBNmD1a+N/3ecMLeMBgfcK+xzsjdLDT6oHt+DFPyeqUbDA== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-syntax-dynamic-import" "^7.8.3" -"@babel/plugin-transform-exponentiation-operator@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz#ea0d978f6b9232ba4722f3dbecdd18f450babd18" - integrity sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ== +"@babel/plugin-transform-exponentiation-operator@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.1.tgz#6650ebeb5bd5c012d5f5f90a26613a08162e8ba4" + integrity sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw== dependencies: "@babel/helper-builder-binary-assignment-operator-visitor" "^7.22.15" - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-export-namespace-from@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz#084c7b25e9a5c8271e987a08cf85807b80283191" - integrity sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ== +"@babel/plugin-transform-export-namespace-from@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.1.tgz#f033541fc036e3efb2dcb58eedafd4f6b8078acd" + integrity sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" -"@babel/plugin-transform-flow-strip-types@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.23.3.tgz#cfa7ca159cc3306fab526fc67091556b51af26ff" - integrity sha512-26/pQTf9nQSNVJCrLB1IkHUKyPxR+lMrH2QDPG89+Znu9rAMbtrybdbWeE9bb7gzjmE5iXHEY+e0HUwM6Co93Q== +"@babel/plugin-transform-flow-strip-types@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.24.1.tgz#fa8d0a146506ea195da1671d38eed459242b2dcc" + integrity sha512-iIYPIWt3dUmUKKE10s3W+jsQ3icFkw0JyRVyY1B7G4yK/nngAOHLVx8xlhA6b/Jzl/Y0nis8gjqhqKtRDQqHWQ== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - "@babel/plugin-syntax-flow" "^7.23.3" + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/plugin-syntax-flow" "^7.24.1" -"@babel/plugin-transform-for-of@^7.23.6": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.6.tgz#81c37e24171b37b370ba6aaffa7ac86bcb46f94e" - integrity sha512-aYH4ytZ0qSuBbpfhuofbg/e96oQ7U2w1Aw/UQmKT+1l39uEhUPoFS3fHevDc1G0OvewyDudfMKY1OulczHzWIw== +"@babel/plugin-transform-for-of@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.1.tgz#67448446b67ab6c091360ce3717e7d3a59e202fd" + integrity sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" -"@babel/plugin-transform-function-name@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz#8f424fcd862bf84cb9a1a6b42bc2f47ed630f8dc" - integrity sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw== +"@babel/plugin-transform-function-name@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.1.tgz#8cba6f7730626cc4dfe4ca2fa516215a0592b361" + integrity sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA== dependencies: - "@babel/helper-compilation-targets" "^7.22.15" + "@babel/helper-compilation-targets" "^7.23.6" "@babel/helper-function-name" "^7.23.0" - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-json-strings@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.23.4.tgz#a871d9b6bd171976efad2e43e694c961ffa3714d" - integrity sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg== +"@babel/plugin-transform-json-strings@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.1.tgz#08e6369b62ab3e8a7b61089151b161180c8299f7" + integrity sha512-U7RMFmRvoasscrIFy5xA4gIp8iWnWubnKkKuUGJjsuOH7GfbMkB+XZzeslx2kLdEGdOJDamEmCqOks6e8nv8DQ== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-syntax-json-strings" "^7.8.3" -"@babel/plugin-transform-literals@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz#8214665f00506ead73de157eba233e7381f3beb4" - integrity sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ== +"@babel/plugin-transform-literals@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.1.tgz#0a1982297af83e6b3c94972686067df588c5c096" + integrity sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-logical-assignment-operators@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.4.tgz#e599f82c51d55fac725f62ce55d3a0886279ecb5" - integrity sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg== +"@babel/plugin-transform-logical-assignment-operators@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.1.tgz#719d8aded1aa94b8fb34e3a785ae8518e24cfa40" + integrity sha512-OhN6J4Bpz+hIBqItTeWJujDOfNP+unqv/NJgyhlpSqgBTPm37KkMmZV6SYcOj+pnDbdcl1qRGV/ZiIjX9Iy34w== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" -"@babel/plugin-transform-member-expression-literals@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz#e37b3f0502289f477ac0e776b05a833d853cabcc" - integrity sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag== +"@babel/plugin-transform-member-expression-literals@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.1.tgz#896d23601c92f437af8b01371ad34beb75df4489" + integrity sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-modules-amd@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz#e19b55436a1416829df0a1afc495deedfae17f7d" - integrity sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw== +"@babel/plugin-transform-modules-amd@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.1.tgz#b6d829ed15258536977e9c7cc6437814871ffa39" + integrity sha512-lAxNHi4HVtjnHd5Rxg3D5t99Xm6H7b04hUS7EHIXcUl2EV4yl1gWdqZrNzXnSrHveL9qMdbODlLF55mvgjAfaQ== dependencies: "@babel/helper-module-transforms" "^7.23.3" - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-modules-commonjs@^7.23.0", "@babel/plugin-transform-modules-commonjs@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz#661ae831b9577e52be57dd8356b734f9700b53b4" - integrity sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA== +"@babel/plugin-transform-modules-commonjs@^7.23.0", "@babel/plugin-transform-modules-commonjs@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz#e71ba1d0d69e049a22bf90b3867e263823d3f1b9" + integrity sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw== dependencies: "@babel/helper-module-transforms" "^7.23.3" - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/helper-simple-access" "^7.22.5" -"@babel/plugin-transform-modules-systemjs@^7.23.9": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.9.tgz#105d3ed46e4a21d257f83a2f9e2ee4203ceda6be" - integrity sha512-KDlPRM6sLo4o1FkiSlXoAa8edLXFsKKIda779fbLrvmeuc3itnjCtaO6RrtoaANsIJANj+Vk1zqbZIMhkCAHVw== +"@babel/plugin-transform-modules-systemjs@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.1.tgz#2b9625a3d4e445babac9788daec39094e6b11e3e" + integrity sha512-mqQ3Zh9vFO1Tpmlt8QPnbwGHzNz3lpNEMxQb1kAemn/erstyqw1r9KeOlOfo3y6xAnFEcOv2tSyrXfmMk+/YZA== dependencies: "@babel/helper-hoist-variables" "^7.22.5" "@babel/helper-module-transforms" "^7.23.3" - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/helper-validator-identifier" "^7.22.20" -"@babel/plugin-transform-modules-umd@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz#5d4395fccd071dfefe6585a4411aa7d6b7d769e9" - integrity sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg== +"@babel/plugin-transform-modules-umd@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.1.tgz#69220c66653a19cf2c0872b9c762b9a48b8bebef" + integrity sha512-tuA3lpPj+5ITfcCluy6nWonSL7RvaG0AOTeAuvXqEKS34lnLzXpDb0dcP6K8jD0zWZFNDVly90AGFJPnm4fOYg== dependencies: "@babel/helper-module-transforms" "^7.23.3" - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-transform-named-capturing-groups-regex@^7.22.5": version "7.22.5" @@ -684,223 +693,223 @@ "@babel/helper-create-regexp-features-plugin" "^7.22.5" "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-new-target@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz#5491bb78ed6ac87e990957cea367eab781c4d980" - integrity sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ== +"@babel/plugin-transform-new-target@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.1.tgz#29c59988fa3d0157de1c871a28cd83096363cc34" + integrity sha512-/rurytBM34hYy0HKZQyA0nHbQgQNFm4Q/BOc9Hflxi2X3twRof7NaE5W46j4kQitm7SvACVRXsa6N/tSZxvPug== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-nullish-coalescing-operator@^7.22.11", "@babel/plugin-transform-nullish-coalescing-operator@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz#45556aad123fc6e52189ea749e33ce090637346e" - integrity sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA== +"@babel/plugin-transform-nullish-coalescing-operator@^7.22.11", "@babel/plugin-transform-nullish-coalescing-operator@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.1.tgz#0cd494bb97cb07d428bd651632cb9d4140513988" + integrity sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" -"@babel/plugin-transform-numeric-separator@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.4.tgz#03d08e3691e405804ecdd19dd278a40cca531f29" - integrity sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q== +"@babel/plugin-transform-numeric-separator@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.1.tgz#5bc019ce5b3435c1cadf37215e55e433d674d4e8" + integrity sha512-7GAsGlK4cNL2OExJH1DzmDeKnRv/LXq0eLUSvudrehVA5Rgg4bIrqEUW29FbKMBRT0ztSqisv7kjP+XIC4ZMNw== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-transform-object-rest-spread@^7.24.0": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.0.tgz#7b836ad0088fdded2420ce96d4e1d3ed78b71df1" - integrity sha512-y/yKMm7buHpFFXfxVFS4Vk1ToRJDilIa6fKRioB9Vjichv58TDGXTvqV0dN7plobAmTW5eSEGXDngE+Mm+uO+w== +"@babel/plugin-transform-object-rest-spread@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.1.tgz#5a3ce73caf0e7871a02e1c31e8b473093af241ff" + integrity sha512-XjD5f0YqOtebto4HGISLNfiNMTTs6tbkFf2TOqJlYKYmbo+mN9Dnpl4SRoofiziuOWMIyq3sZEUqLo3hLITFEA== dependencies: - "@babel/compat-data" "^7.23.5" "@babel/helper-compilation-targets" "^7.23.6" "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.23.3" + "@babel/plugin-transform-parameters" "^7.24.1" -"@babel/plugin-transform-object-super@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz#81fdb636dcb306dd2e4e8fd80db5b2362ed2ebcd" - integrity sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA== +"@babel/plugin-transform-object-super@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.1.tgz#e71d6ab13483cca89ed95a474f542bbfc20a0520" + integrity sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - "@babel/helper-replace-supers" "^7.22.20" + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-replace-supers" "^7.24.1" -"@babel/plugin-transform-optional-catch-binding@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.4.tgz#318066de6dacce7d92fa244ae475aa8d91778017" - integrity sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A== +"@babel/plugin-transform-optional-catch-binding@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.1.tgz#92a3d0efe847ba722f1a4508669b23134669e2da" + integrity sha512-oBTH7oURV4Y+3EUrf6cWn1OHio3qG/PVwO5J03iSJmBg6m2EhKjkAu/xuaXaYwWW9miYtvbWv4LNf0AmR43LUA== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" -"@babel/plugin-transform-optional-chaining@^7.23.0", "@babel/plugin-transform-optional-chaining@^7.23.3", "@babel/plugin-transform-optional-chaining@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz#6acf61203bdfc4de9d4e52e64490aeb3e52bd017" - integrity sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA== +"@babel/plugin-transform-optional-chaining@^7.23.0", "@babel/plugin-transform-optional-chaining@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.1.tgz#26e588acbedce1ab3519ac40cc748e380c5291e6" + integrity sha512-n03wmDt+987qXwAgcBlnUUivrZBPZ8z1plL0YvgQalLm+ZE5BMhGm94jhxXtA1wzv1Cu2aaOv1BM9vbVttrzSg== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" "@babel/plugin-syntax-optional-chaining" "^7.8.3" -"@babel/plugin-transform-parameters@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz#83ef5d1baf4b1072fa6e54b2b0999a7b2527e2af" - integrity sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw== +"@babel/plugin-transform-parameters@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.1.tgz#983c15d114da190506c75b616ceb0f817afcc510" + integrity sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-private-methods@^7.22.5", "@babel/plugin-transform-private-methods@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz#b2d7a3c97e278bfe59137a978d53b2c2e038c0e4" - integrity sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g== +"@babel/plugin-transform-private-methods@^7.22.5", "@babel/plugin-transform-private-methods@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.1.tgz#a0faa1ae87eff077e1e47a5ec81c3aef383dc15a" + integrity sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw== dependencies: - "@babel/helper-create-class-features-plugin" "^7.22.15" - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-create-class-features-plugin" "^7.24.1" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-private-property-in-object@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz#3ec711d05d6608fd173d9b8de39872d8dbf68bf5" - integrity sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A== +"@babel/plugin-transform-private-property-in-object@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.1.tgz#756443d400274f8fb7896742962cc1b9f25c1f6a" + integrity sha512-pTHxDVa0BpUbvAgX3Gat+7cSciXqUcY9j2VZKTbSB6+VQGpNgNO9ailxTGHSXlqOnX1Hcx1Enme2+yv7VqP9bg== dependencies: "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-create-class-features-plugin" "^7.22.15" - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-create-class-features-plugin" "^7.24.1" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-syntax-private-property-in-object" "^7.14.5" -"@babel/plugin-transform-property-literals@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz#54518f14ac4755d22b92162e4a852d308a560875" - integrity sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw== +"@babel/plugin-transform-property-literals@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.1.tgz#d6a9aeab96f03749f4eebeb0b6ea8e90ec958825" + integrity sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-transform-react-jsx-self@^7.18.6", "@babel/plugin-transform-react-jsx-self@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz#ed3e7dadde046cce761a8e3cf003a13d1a7972d9" - integrity sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ== + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.24.1.tgz#a21d866d8167e752c6a7c4555dba8afcdfce6268" + integrity sha512-kDJgnPujTmAZ/9q2CN4m2/lRsUUPDvsG3+tSHWUJIzMGTt5U/b/fwWd3RO3n+5mjLrsBrVa5eKFRVSQbi3dF1w== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-transform-react-jsx-source@^7.19.6", "@babel/plugin-transform-react-jsx-source@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz#03527006bdc8775247a78643c51d4e715fe39a3e" - integrity sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g== + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.24.1.tgz#a2dedb12b09532846721b5df99e52ef8dc3351d0" + integrity sha512-1v202n7aUq4uXAieRTKcwPzNyphlCuqHHDcdSNc+vdhoTEZcFMh+L5yZuCmGaIO7bs1nJUNfHB89TZyoL48xNA== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-regenerator@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz#141afd4a2057298602069fce7f2dc5173e6c561c" - integrity sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ== +"@babel/plugin-transform-regenerator@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.1.tgz#625b7545bae52363bdc1fbbdc7252b5046409c8c" + integrity sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" regenerator-transform "^0.15.2" -"@babel/plugin-transform-reserved-words@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz#4130dcee12bd3dd5705c587947eb715da12efac8" - integrity sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg== +"@babel/plugin-transform-reserved-words@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.1.tgz#8de729f5ecbaaf5cf83b67de13bad38a21be57c1" + integrity sha512-JAclqStUfIwKN15HrsQADFgeZt+wexNQ0uLhuqvqAUFoqPMjEcFCYZBhq0LUdz6dZK/mD+rErhW71fbx8RYElg== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-shorthand-properties@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz#97d82a39b0e0c24f8a981568a8ed851745f59210" - integrity sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg== +"@babel/plugin-transform-shorthand-properties@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.1.tgz#ba9a09144cf55d35ec6b93a32253becad8ee5b55" + integrity sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-spread@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz#41d17aacb12bde55168403c6f2d6bdca563d362c" - integrity sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg== +"@babel/plugin-transform-spread@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.1.tgz#a1acf9152cbf690e4da0ba10790b3ac7d2b2b391" + integrity sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" -"@babel/plugin-transform-sticky-regex@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz#dec45588ab4a723cb579c609b294a3d1bd22ff04" - integrity sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg== +"@babel/plugin-transform-sticky-regex@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.1.tgz#f03e672912c6e203ed8d6e0271d9c2113dc031b9" + integrity sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-template-literals@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz#5f0f028eb14e50b5d0f76be57f90045757539d07" - integrity sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg== +"@babel/plugin-transform-template-literals@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.1.tgz#15e2166873a30d8617e3e2ccadb86643d327aab7" + integrity sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-typeof-symbol@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz#9dfab97acc87495c0c449014eb9c547d8966bca4" - integrity sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ== +"@babel/plugin-transform-typeof-symbol@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.1.tgz#6831f78647080dec044f7e9f68003d99424f94c7" + integrity sha512-CBfU4l/A+KruSUoW+vTQthwcAdwuqbpRNB8HQKlZABwHRhsdHZ9fezp4Sn18PeAlYxTNiLMlx4xUBV3AWfg1BA== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-typescript@^7.23.3": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.23.6.tgz#aa36a94e5da8d94339ae3a4e22d40ed287feb34c" - integrity sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA== +"@babel/plugin-transform-typescript@^7.24.1": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.4.tgz#03e0492537a4b953e491f53f2bc88245574ebd15" + integrity sha512-79t3CQ8+oBGk/80SQ8MN3Bs3obf83zJ0YZjDmDaEZN8MqhMI760apl5z6a20kFeMXBwJX99VpKT8CKxEBp5H1g== dependencies: "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-create-class-features-plugin" "^7.23.6" - "@babel/helper-plugin-utils" "^7.22.5" - "@babel/plugin-syntax-typescript" "^7.23.3" + "@babel/helper-create-class-features-plugin" "^7.24.4" + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/plugin-syntax-typescript" "^7.24.1" -"@babel/plugin-transform-unicode-escapes@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz#1f66d16cab01fab98d784867d24f70c1ca65b925" - integrity sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q== +"@babel/plugin-transform-unicode-escapes@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.1.tgz#fb3fa16676549ac7c7449db9b342614985c2a3a4" + integrity sha512-RlkVIcWT4TLI96zM660S877E7beKlQw7Ig+wqkKBiWfj0zH5Q4h50q6er4wzZKRNSYpfo6ILJ+hrJAGSX2qcNw== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-unicode-property-regex@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz#19e234129e5ffa7205010feec0d94c251083d7ad" - integrity sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA== +"@babel/plugin-transform-unicode-property-regex@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.1.tgz#56704fd4d99da81e5e9f0c0c93cabd91dbc4889e" + integrity sha512-Ss4VvlfYV5huWApFsF8/Sq0oXnGO+jB+rijFEFugTd3cwSObUSnUi88djgR5528Csl0uKlrI331kRqe56Ov2Ng== dependencies: "@babel/helper-create-regexp-features-plugin" "^7.22.15" - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-unicode-regex@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz#26897708d8f42654ca4ce1b73e96140fbad879dc" - integrity sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw== +"@babel/plugin-transform-unicode-regex@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.1.tgz#57c3c191d68f998ac46b708380c1ce4d13536385" + integrity sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g== dependencies: "@babel/helper-create-regexp-features-plugin" "^7.22.15" - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-unicode-sets-regex@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz#4fb6f0a719c2c5859d11f6b55a050cc987f3799e" - integrity sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw== +"@babel/plugin-transform-unicode-sets-regex@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.1.tgz#c1ea175b02afcffc9cf57a9c4658326625165b7f" + integrity sha512-fqj4WuzzS+ukpgerpAoOnMfQXwUHFxXUZUE84oL2Kao2N8uSlvcpnAidKASgsNgzZHBsHWvcm8s9FPWUhAb8fA== dependencies: "@babel/helper-create-regexp-features-plugin" "^7.22.15" - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/preset-env@^7.23.2": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.24.0.tgz#11536a7f4b977294f0bdfad780f01a8ac8e183fc" - integrity sha512-ZxPEzV9IgvGn73iK0E6VB9/95Nd7aMFpbE0l8KQFDG70cOV9IxRP7Y2FUPmlK0v6ImlLqYX50iuZ3ZTVhOF2lA== + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.24.4.tgz#46dbbcd608771373b88f956ffb67d471dce0d23b" + integrity sha512-7Kl6cSmYkak0FK/FXjSEnLJ1N9T/WA2RkMhu17gZ/dsxKJUuTYNIylahPTzqpLyJN4WhDif8X0XK1R8Wsguo/A== dependencies: - "@babel/compat-data" "^7.23.5" + "@babel/compat-data" "^7.24.4" "@babel/helper-compilation-targets" "^7.23.6" "@babel/helper-plugin-utils" "^7.24.0" "@babel/helper-validator-option" "^7.23.5" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.23.3" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.23.3" - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.23.7" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.24.4" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.24.1" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.24.1" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.24.1" "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-class-properties" "^7.12.13" "@babel/plugin-syntax-class-static-block" "^7.14.5" "@babel/plugin-syntax-dynamic-import" "^7.8.3" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-import-assertions" "^7.23.3" - "@babel/plugin-syntax-import-attributes" "^7.23.3" + "@babel/plugin-syntax-import-assertions" "^7.24.1" + "@babel/plugin-syntax-import-attributes" "^7.24.1" "@babel/plugin-syntax-import-meta" "^7.10.4" "@babel/plugin-syntax-json-strings" "^7.8.3" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" @@ -912,69 +921,69 @@ "@babel/plugin-syntax-private-property-in-object" "^7.14.5" "@babel/plugin-syntax-top-level-await" "^7.14.5" "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" - "@babel/plugin-transform-arrow-functions" "^7.23.3" - "@babel/plugin-transform-async-generator-functions" "^7.23.9" - "@babel/plugin-transform-async-to-generator" "^7.23.3" - "@babel/plugin-transform-block-scoped-functions" "^7.23.3" - "@babel/plugin-transform-block-scoping" "^7.23.4" - "@babel/plugin-transform-class-properties" "^7.23.3" - "@babel/plugin-transform-class-static-block" "^7.23.4" - "@babel/plugin-transform-classes" "^7.23.8" - "@babel/plugin-transform-computed-properties" "^7.23.3" - "@babel/plugin-transform-destructuring" "^7.23.3" - "@babel/plugin-transform-dotall-regex" "^7.23.3" - "@babel/plugin-transform-duplicate-keys" "^7.23.3" - "@babel/plugin-transform-dynamic-import" "^7.23.4" - "@babel/plugin-transform-exponentiation-operator" "^7.23.3" - "@babel/plugin-transform-export-namespace-from" "^7.23.4" - "@babel/plugin-transform-for-of" "^7.23.6" - "@babel/plugin-transform-function-name" "^7.23.3" - "@babel/plugin-transform-json-strings" "^7.23.4" - "@babel/plugin-transform-literals" "^7.23.3" - "@babel/plugin-transform-logical-assignment-operators" "^7.23.4" - "@babel/plugin-transform-member-expression-literals" "^7.23.3" - "@babel/plugin-transform-modules-amd" "^7.23.3" - "@babel/plugin-transform-modules-commonjs" "^7.23.3" - "@babel/plugin-transform-modules-systemjs" "^7.23.9" - "@babel/plugin-transform-modules-umd" "^7.23.3" + "@babel/plugin-transform-arrow-functions" "^7.24.1" + "@babel/plugin-transform-async-generator-functions" "^7.24.3" + "@babel/plugin-transform-async-to-generator" "^7.24.1" + "@babel/plugin-transform-block-scoped-functions" "^7.24.1" + "@babel/plugin-transform-block-scoping" "^7.24.4" + "@babel/plugin-transform-class-properties" "^7.24.1" + "@babel/plugin-transform-class-static-block" "^7.24.4" + "@babel/plugin-transform-classes" "^7.24.1" + "@babel/plugin-transform-computed-properties" "^7.24.1" + "@babel/plugin-transform-destructuring" "^7.24.1" + "@babel/plugin-transform-dotall-regex" "^7.24.1" + "@babel/plugin-transform-duplicate-keys" "^7.24.1" + "@babel/plugin-transform-dynamic-import" "^7.24.1" + "@babel/plugin-transform-exponentiation-operator" "^7.24.1" + "@babel/plugin-transform-export-namespace-from" "^7.24.1" + "@babel/plugin-transform-for-of" "^7.24.1" + "@babel/plugin-transform-function-name" "^7.24.1" + "@babel/plugin-transform-json-strings" "^7.24.1" + "@babel/plugin-transform-literals" "^7.24.1" + "@babel/plugin-transform-logical-assignment-operators" "^7.24.1" + "@babel/plugin-transform-member-expression-literals" "^7.24.1" + "@babel/plugin-transform-modules-amd" "^7.24.1" + "@babel/plugin-transform-modules-commonjs" "^7.24.1" + "@babel/plugin-transform-modules-systemjs" "^7.24.1" + "@babel/plugin-transform-modules-umd" "^7.24.1" "@babel/plugin-transform-named-capturing-groups-regex" "^7.22.5" - "@babel/plugin-transform-new-target" "^7.23.3" - "@babel/plugin-transform-nullish-coalescing-operator" "^7.23.4" - "@babel/plugin-transform-numeric-separator" "^7.23.4" - "@babel/plugin-transform-object-rest-spread" "^7.24.0" - "@babel/plugin-transform-object-super" "^7.23.3" - "@babel/plugin-transform-optional-catch-binding" "^7.23.4" - "@babel/plugin-transform-optional-chaining" "^7.23.4" - "@babel/plugin-transform-parameters" "^7.23.3" - "@babel/plugin-transform-private-methods" "^7.23.3" - "@babel/plugin-transform-private-property-in-object" "^7.23.4" - "@babel/plugin-transform-property-literals" "^7.23.3" - "@babel/plugin-transform-regenerator" "^7.23.3" - "@babel/plugin-transform-reserved-words" "^7.23.3" - "@babel/plugin-transform-shorthand-properties" "^7.23.3" - "@babel/plugin-transform-spread" "^7.23.3" - "@babel/plugin-transform-sticky-regex" "^7.23.3" - "@babel/plugin-transform-template-literals" "^7.23.3" - "@babel/plugin-transform-typeof-symbol" "^7.23.3" - "@babel/plugin-transform-unicode-escapes" "^7.23.3" - "@babel/plugin-transform-unicode-property-regex" "^7.23.3" - "@babel/plugin-transform-unicode-regex" "^7.23.3" - "@babel/plugin-transform-unicode-sets-regex" "^7.23.3" + "@babel/plugin-transform-new-target" "^7.24.1" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.24.1" + "@babel/plugin-transform-numeric-separator" "^7.24.1" + "@babel/plugin-transform-object-rest-spread" "^7.24.1" + "@babel/plugin-transform-object-super" "^7.24.1" + "@babel/plugin-transform-optional-catch-binding" "^7.24.1" + "@babel/plugin-transform-optional-chaining" "^7.24.1" + "@babel/plugin-transform-parameters" "^7.24.1" + "@babel/plugin-transform-private-methods" "^7.24.1" + "@babel/plugin-transform-private-property-in-object" "^7.24.1" + "@babel/plugin-transform-property-literals" "^7.24.1" + "@babel/plugin-transform-regenerator" "^7.24.1" + "@babel/plugin-transform-reserved-words" "^7.24.1" + "@babel/plugin-transform-shorthand-properties" "^7.24.1" + "@babel/plugin-transform-spread" "^7.24.1" + "@babel/plugin-transform-sticky-regex" "^7.24.1" + "@babel/plugin-transform-template-literals" "^7.24.1" + "@babel/plugin-transform-typeof-symbol" "^7.24.1" + "@babel/plugin-transform-unicode-escapes" "^7.24.1" + "@babel/plugin-transform-unicode-property-regex" "^7.24.1" + "@babel/plugin-transform-unicode-regex" "^7.24.1" + "@babel/plugin-transform-unicode-sets-regex" "^7.24.1" "@babel/preset-modules" "0.1.6-no-external-plugins" - babel-plugin-polyfill-corejs2 "^0.4.8" - babel-plugin-polyfill-corejs3 "^0.9.0" - babel-plugin-polyfill-regenerator "^0.5.5" + babel-plugin-polyfill-corejs2 "^0.4.10" + babel-plugin-polyfill-corejs3 "^0.10.4" + babel-plugin-polyfill-regenerator "^0.6.1" core-js-compat "^3.31.0" semver "^6.3.1" "@babel/preset-flow@^7.22.15": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.24.0.tgz#0de60271b0a439b415501c5b28f685fbcb080e1c" - integrity sha512-cum/nSi82cDaSJ21I4PgLTVlj0OXovFk6GRguJYe/IKg6y6JHLTbJhybtX4k35WT9wdeJfEVjycTixMhBHd0Dg== + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.24.1.tgz#da7196c20c2d7dd4e98cfd8b192fe53b5eb6f0bb" + integrity sha512-sWCV2G9pcqZf+JHyv/RyqEIpFypxdCSxWIxQjpdaQxenNog7cN1pr76hg8u0Fz8Qgg0H4ETkGcJnXL8d4j0PPA== dependencies: "@babel/helper-plugin-utils" "^7.24.0" "@babel/helper-validator-option" "^7.23.5" - "@babel/plugin-transform-flow-strip-types" "^7.23.3" + "@babel/plugin-transform-flow-strip-types" "^7.24.1" "@babel/preset-modules@0.1.6-no-external-plugins": version "0.1.6-no-external-plugins" @@ -986,15 +995,15 @@ esutils "^2.0.2" "@babel/preset-typescript@^7.23.0": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.23.3.tgz#14534b34ed5b6d435aa05f1ae1c5e7adcc01d913" - integrity sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ== + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.24.1.tgz#89bdf13a3149a17b3b2a2c9c62547f06db8845ec" + integrity sha512-1DBaMmRDpuYQBPWD8Pf/WEwCrtgRHxsZnP4mIy9G/X+hFfbI47Q2G4t1Paakld84+qsk2fSsUPMKg71jkoOOaQ== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - "@babel/helper-validator-option" "^7.22.15" - "@babel/plugin-syntax-jsx" "^7.23.3" - "@babel/plugin-transform-modules-commonjs" "^7.23.3" - "@babel/plugin-transform-typescript" "^7.23.3" + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-validator-option" "^7.23.5" + "@babel/plugin-syntax-jsx" "^7.24.1" + "@babel/plugin-transform-modules-commonjs" "^7.24.1" + "@babel/plugin-transform-typescript" "^7.24.1" "@babel/register@^7.22.15": version "7.23.7" @@ -1013,17 +1022,17 @@ integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== "@babel/runtime-corejs3@^7.12.1": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.24.0.tgz#34243e29e369a762dd2a356fee65c3767973828a" - integrity sha512-HxiRMOncx3ly6f3fcZ1GVKf+/EROcI9qwPgmij8Czqy6Okm/0T37T4y2ZIlLUuEUFjtM7NRsfdCO8Y3tAiJZew== + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.24.4.tgz#b9ebe728087cfbb22bbaccc6f9a70d69834124a0" + integrity sha512-VOQOexSilscN24VEY810G/PqtpFvx/z6UqDIjIWbDe2368HhDLkYN5TYwaEz/+eRCUkhJ2WaNLLmQAlxzfWj4w== dependencies: core-js-pure "^3.30.2" regenerator-runtime "^0.14.0" "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.5", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.23.8", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.0.tgz#584c450063ffda59697021430cb47101b085951e" - integrity sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw== + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.4.tgz#de795accd698007a66ba44add6cc86542aff1edd" + integrity sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA== dependencies: regenerator-runtime "^0.14.0" @@ -1036,23 +1045,23 @@ "@babel/parser" "^7.24.0" "@babel/types" "^7.24.0" -"@babel/traverse@^7.18.9", "@babel/traverse@^7.23.2", "@babel/traverse@^7.24.0", "@babel/traverse@^7.4.5", "@babel/traverse@^7.8.3": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.0.tgz#4a408fbf364ff73135c714a2ab46a5eab2831b1e" - integrity sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw== +"@babel/traverse@^7.18.9", "@babel/traverse@^7.23.2", "@babel/traverse@^7.24.1", "@babel/traverse@^7.4.5", "@babel/traverse@^7.8.3": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.1.tgz#d65c36ac9dd17282175d1e4a3c49d5b7988f530c" + integrity sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ== dependencies: - "@babel/code-frame" "^7.23.5" - "@babel/generator" "^7.23.6" + "@babel/code-frame" "^7.24.1" + "@babel/generator" "^7.24.1" "@babel/helper-environment-visitor" "^7.22.20" "@babel/helper-function-name" "^7.23.0" "@babel/helper-hoist-variables" "^7.22.5" "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.24.0" + "@babel/parser" "^7.24.1" "@babel/types" "^7.24.0" debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.18.9", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.19", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.6", "@babel/types@^7.24.0", "@babel/types@^7.4.4": +"@babel/types@^7.0.0", "@babel/types@^7.18.9", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.19", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.0", "@babel/types@^7.4.4": version "7.24.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.0.tgz#3b951f435a92e7333eba05b7566fd297960ea1bf" integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w== @@ -1081,87 +1090,87 @@ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0" integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== -"@csstools/cascade-layer-name-parser@^1.0.8": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-1.0.8.tgz#24d841d80e78f6c2970a36d53e6b58e8fcea41f6" - integrity sha512-xHxXavWvXB5nAA9IvZtjEzkONM3hPXpxqYK4cEw60LcqPiFjq7ZlEFxOyYFPrG4UdANKtnucNtRVDy7frjq6AA== +"@csstools/cascade-layer-name-parser@^1.0.9": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-1.0.9.tgz#7093f9c26fd92dee87d853a97de0647c5a8c4262" + integrity sha512-RRqNjxTZDUhx7pxYOBG/AkCVmPS3zYzfE47GEhIGkFuWFTQGJBgWOUUkKNo5MfxIfjDz5/1L3F3rF1oIsYaIpw== -"@csstools/color-helpers@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@csstools/color-helpers/-/color-helpers-4.0.0.tgz#a1d6ffcefe5c1d389cbcca15f46da3cdaf241443" - integrity sha512-wjyXB22/h2OvxAr3jldPB7R7kjTUEzopvjitS8jWtyd8fN6xJ8vy1HnHu0ZNfEkqpBJgQ76Q+sBDshWcMvTa/w== +"@csstools/color-helpers@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@csstools/color-helpers/-/color-helpers-4.2.0.tgz#e8629ca9dce03a3a309506e7892b7f862673cf85" + integrity sha512-hJJrSBzbfGxUsaR6X4Bzd/FLx0F1ulKnR5ljY9AiXCtsR+H+zSWQDFWlKES1BRaVZTDHLpIIHS9K2o0h+JLlrg== "@csstools/convert-colors@^1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw== -"@csstools/css-calc@^1.1.7": - version "1.1.7" - resolved "https://registry.yarnpkg.com/@csstools/css-calc/-/css-calc-1.1.7.tgz#89b5cde81ecb4686d9abd66b7eb54015cf39c442" - integrity sha512-+7bUzB5I4cI97tKmBJA8ilTl/YRo6VAOdlrnd/4x2NyK60nvYurGKa5TZpE1zcgIrTC97iJRE0/V65feyFytuw== +"@csstools/css-calc@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@csstools/css-calc/-/css-calc-1.2.0.tgz#a45145a868e644c31c79baf74c8de64fd09b3415" + integrity sha512-iQqIW5vDPqQdLx07/atCuNKDprhIWjB0b8XRhUyXZWBZYUG+9mNyFwyu30rypX84WLevVo25NYW2ipxR8WyseQ== -"@csstools/css-color-parser@^1.5.2": - version "1.5.2" - resolved "https://registry.yarnpkg.com/@csstools/css-color-parser/-/css-color-parser-1.5.2.tgz#4fdf8e23960b4724913f7cbfd4f413eb8f35724b" - integrity sha512-5GEkuuUxD5dael3xoWjyf7gAPAi4pwm8X8JW/nUMhxntGY4Wo4Lp7vKlex4V5ZgTfAoov14rZFsZyOantdTatg== +"@csstools/css-color-parser@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@csstools/css-color-parser/-/css-color-parser-2.0.0.tgz#8e75d1b4a857317f537b3c0a223be0ef1735bbdb" + integrity sha512-0/v6OPpcg+b8TJT2N1Rcp0oH5xEvVOU5K2qDkaR3IMHNXuJ7XfVCQLINt3Cuj8mr54DbilEoZ9uvAmHBoZ//Fw== dependencies: - "@csstools/color-helpers" "^4.0.0" - "@csstools/css-calc" "^1.1.7" + "@csstools/color-helpers" "^4.2.0" + "@csstools/css-calc" "^1.2.0" -"@csstools/css-parser-algorithms@^2.6.0": - version "2.6.0" - resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.6.0.tgz#b45d3c7cbdd4214261724c82f96e33c746fedd58" - integrity sha512-YfEHq0eRH98ffb5/EsrrDspVWAuph6gDggAE74ZtjecsmyyWpW768hOyiONa8zwWGbIWYfa2Xp4tRTrpQQ00CQ== +"@csstools/css-parser-algorithms@^2.6.1": + version "2.6.1" + resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.6.1.tgz#c45440d1efa2954006748a01697072dae5881bcd" + integrity sha512-ubEkAaTfVZa+WwGhs5jbo5Xfqpeaybr/RvWzvFxRs4jfq16wH8l8Ty/QEEpINxll4xhuGfdMbipRyz5QZh9+FA== -"@csstools/css-tokenizer@^2.2.3": - version "2.2.3" - resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-2.2.3.tgz#b099d543ea57b64f495915a095ead583866c50c6" - integrity sha512-pp//EvZ9dUmGuGtG1p+n17gTHEOqu9jO+FiCUjNN3BDmyhdA2Jq9QsVeR7K8/2QCK17HSsioPlTW9ZkzoWb3Lg== +"@csstools/css-tokenizer@^2.2.4": + version "2.2.4" + resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-2.2.4.tgz#a4b8718ed7fcd2dcd555de16b31ca59ad4b96a06" + integrity sha512-PuWRAewQLbDhGeTvFuq2oClaSCKPIBmHyIobCV39JHRYN0byDcUWJl5baPeNUcqrjtdMNqFooE0FGl31I3JOqw== -"@csstools/media-query-list-parser@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.8.tgz#36157fbe54ea30d5f2b1767c69fcdf92048a7b1d" - integrity sha512-DiD3vG5ciNzeuTEoh74S+JMjQDs50R3zlxHnBnfd04YYfA/kh2KiBCGhzqLxlJcNq+7yNQ3stuZZYLX6wK/U2g== +"@csstools/media-query-list-parser@^2.1.9": + version "2.1.9" + resolved "https://registry.yarnpkg.com/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.9.tgz#feb4b7268f998956eb3ded69507869e73d005dda" + integrity sha512-qqGuFfbn4rUmyOB0u8CVISIp5FfJ5GAR3mBrZ9/TKndHakdnm6pY0L/fbLcpPnrzwCyyTEZl1nUcXAYHEWneTA== "@csstools/postcss-cascade-layers@^4.0.1": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-4.0.3.tgz#2805dbb8dec661101928298b2e16599edf3c2bea" - integrity sha512-RbkQoOH23yGhWVetgBTwFgIOHEyU2tKMN7blTz/YAKKabR6tr9pP7mYS23Q9snFY2hr8WSaV8Le64KdM9BtUSA== + version "4.0.4" + resolved "https://registry.yarnpkg.com/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-4.0.4.tgz#0f20882d4f528a8128b0855ce63c3e6eee6d1b44" + integrity sha512-MKErv8lpEwVmAcAwidY1Kfd3oWrh2Q14kxHs9xn26XzjP/PrcdngWq63lJsZeMlBY7o+WlEOeE+FP6zPzeY2uw== dependencies: - "@csstools/selector-specificity" "^3.0.2" + "@csstools/selector-specificity" "^3.0.3" postcss-selector-parser "^6.0.13" "@csstools/postcss-color-function@^3.0.7": - version "3.0.10" - resolved "https://registry.yarnpkg.com/@csstools/postcss-color-function/-/postcss-color-function-3.0.10.tgz#708d34f24daf5ff9978d2d4e8d3413f638a41158" - integrity sha512-jxiXmSl4ZYX8KewFjL5ef6of9uW73VkaHeDb2tqb5q4ZDPYxjusNX1KJ8UXY8+7ydqS5QBo42tVMrSMGy+rDmw== - dependencies: - "@csstools/css-color-parser" "^1.5.2" - "@csstools/css-parser-algorithms" "^2.6.0" - "@csstools/css-tokenizer" "^2.2.3" - "@csstools/postcss-progressive-custom-properties" "^3.1.0" + version "3.0.14" + resolved "https://registry.yarnpkg.com/@csstools/postcss-color-function/-/postcss-color-function-3.0.14.tgz#b148f611626a0b6dfd66319b7921b7419b2318a0" + integrity sha512-joGAf5bT3Jg1CpybupMJ4DwNg/VNjmLWZoWMDmX0MTy/ftHA1Qr4+CslqTT4AA1n6Dx4Wa+DSMGPrDLHtRP0jg== + dependencies: + "@csstools/css-color-parser" "^2.0.0" + "@csstools/css-parser-algorithms" "^2.6.1" + "@csstools/css-tokenizer" "^2.2.4" + "@csstools/postcss-progressive-custom-properties" "^3.2.0" "@csstools/utilities" "^1.0.0" "@csstools/postcss-color-mix-function@^2.0.7": - version "2.0.10" - resolved "https://registry.yarnpkg.com/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-2.0.10.tgz#fd86d1f3b334fb59a3558d33f121ce5dff758da8" - integrity sha512-zeD856+FDCUjB077pPS+Z9OnTQnqpiJrao3TW+sasCb/gJ3vZCX7sRSRFsRUo0/MntTtJu9hkKv9eMkFmfjydA== + version "2.0.14" + resolved "https://registry.yarnpkg.com/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-2.0.14.tgz#5baec0e7b4ef488e830ef702c85f1d45ef2193df" + integrity sha512-ZLbgtdhyuOoWoRo/W8jFv68q+IMgTJHOAI+WunRbrRPqI+vJ0K2rud/lS9Se5urzM/imVKs/kz0Uobm5Yj4HUg== dependencies: - "@csstools/css-color-parser" "^1.5.2" - "@csstools/css-parser-algorithms" "^2.6.0" - "@csstools/css-tokenizer" "^2.2.3" - "@csstools/postcss-progressive-custom-properties" "^3.1.0" + "@csstools/css-color-parser" "^2.0.0" + "@csstools/css-parser-algorithms" "^2.6.1" + "@csstools/css-tokenizer" "^2.2.4" + "@csstools/postcss-progressive-custom-properties" "^3.2.0" "@csstools/utilities" "^1.0.0" "@csstools/postcss-exponential-functions@^1.0.1": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-1.0.4.tgz#c8c3773d4f761428717b80803302722ed2f849f1" - integrity sha512-frMf0CFVnZoGEKAHlxLy3s4g/tpjyFn5+A+h895UJNm9Uc+ewGT7+EeK7Kh9IHH4pD4FkaGW1vOQtER00PLurQ== + version "1.0.5" + resolved "https://registry.yarnpkg.com/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-1.0.5.tgz#ac6f9e545cf6bbf9d6bad11e655ca693c4982e58" + integrity sha512-7S7I7KgwHWQYzJJAoIjRtUf7DQs1dxipeg1A6ikZr0PYapNJX7UHz0evlpE67SQqYj1xBs70gpG7xUv3uLp4PA== dependencies: - "@csstools/css-calc" "^1.1.7" - "@csstools/css-parser-algorithms" "^2.6.0" - "@csstools/css-tokenizer" "^2.2.3" + "@csstools/css-calc" "^1.2.0" + "@csstools/css-parser-algorithms" "^2.6.1" + "@csstools/css-tokenizer" "^2.2.4" "@csstools/postcss-font-format-keywords@^3.0.0": version "3.0.2" @@ -1172,42 +1181,42 @@ postcss-value-parser "^4.2.0" "@csstools/postcss-gamut-mapping@^1.0.0": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-1.0.3.tgz#e5323fb1bf46f6d32d760e98028a8e9da9d8fe4b" - integrity sha512-P0+ude1KyCy9LXOe2pHJmpcXK4q/OQbr2Sn2wQSssMw0rALGmny2MfHiCqEu8n6mf2cN6lWDZdzY8enBk8WHXQ== + version "1.0.7" + resolved "https://registry.yarnpkg.com/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-1.0.7.tgz#6413d3f9e2612e9419cc9978aa36f87895f74e88" + integrity sha512-vrsHsl5TN6NB5CT0rPG6JE9V2GLFftcmPtF/k4cWT4gyVMCsDyS9wEVl82sgvh/JQ32TaUo6bh8Ndl+XRJqGQw== dependencies: - "@csstools/css-color-parser" "^1.5.2" - "@csstools/css-parser-algorithms" "^2.6.0" - "@csstools/css-tokenizer" "^2.2.3" + "@csstools/css-color-parser" "^2.0.0" + "@csstools/css-parser-algorithms" "^2.6.1" + "@csstools/css-tokenizer" "^2.2.4" "@csstools/postcss-gradients-interpolation-method@^4.0.7": - version "4.0.11" - resolved "https://registry.yarnpkg.com/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-4.0.11.tgz#4e6cf5d6917672058d532d963c709e3776b9ab36" - integrity sha512-LFom5jCVUfzF+iuiOZvhvX7RRN8vc+tKpcKo9s4keEBAU2mPwV5/Fgz5iylEfXP/DZbEdq2C0At20urMi/lupw== - dependencies: - "@csstools/css-color-parser" "^1.5.2" - "@csstools/css-parser-algorithms" "^2.6.0" - "@csstools/css-tokenizer" "^2.2.3" - "@csstools/postcss-progressive-custom-properties" "^3.1.0" + version "4.0.15" + resolved "https://registry.yarnpkg.com/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-4.0.15.tgz#6cb6785733da39101e02a8803d374c2fd9c45c2b" + integrity sha512-0xQ5r4WU/6W2lDmnOTx9liC1Cq6RSnrkEzqX7d0cRA3fz5hjC276pA0nLMoAiY3vtAp0u71nTk/3TRdnCx/OUw== + dependencies: + "@csstools/css-color-parser" "^2.0.0" + "@csstools/css-parser-algorithms" "^2.6.1" + "@csstools/css-tokenizer" "^2.2.4" + "@csstools/postcss-progressive-custom-properties" "^3.2.0" "@csstools/utilities" "^1.0.0" "@csstools/postcss-hwb-function@^3.0.6": - version "3.0.9" - resolved "https://registry.yarnpkg.com/@csstools/postcss-hwb-function/-/postcss-hwb-function-3.0.9.tgz#15c5b8d43cffe62283b6175494188d6957712d91" - integrity sha512-S3/Z+mGHWIKAex7DLsHFDiku5lBEK34avT2My6sGPNCXB38TZjrKI0rd7JdN9oulem5sn+CU7oONyIftui24oQ== - dependencies: - "@csstools/css-color-parser" "^1.5.2" - "@csstools/css-parser-algorithms" "^2.6.0" - "@csstools/css-tokenizer" "^2.2.3" - "@csstools/postcss-progressive-custom-properties" "^3.1.0" + version "3.0.13" + resolved "https://registry.yarnpkg.com/@csstools/postcss-hwb-function/-/postcss-hwb-function-3.0.13.tgz#b83c0a4aa962c7182eececaec3d88cc152e8c16a" + integrity sha512-f44tgkFSxJBGm8UjlkAfBP7xE2x2XFFdvNdedHl8jpx2pQcW8a50OT3yeMnM3NB9Y2Ynd7Wn8iXARiV/IHoKvw== + dependencies: + "@csstools/css-color-parser" "^2.0.0" + "@csstools/css-parser-algorithms" "^2.6.1" + "@csstools/css-tokenizer" "^2.2.4" + "@csstools/postcss-progressive-custom-properties" "^3.2.0" "@csstools/utilities" "^1.0.0" "@csstools/postcss-ic-unit@^3.0.2": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@csstools/postcss-ic-unit/-/postcss-ic-unit-3.0.4.tgz#9f4bffaed6ece2a79e1e15fbd7ba6aea8d61c851" - integrity sha512-OB6ojl33/TQHhjVx1NI+n3EnYbdUM6Q/mSUv3WFATdcz7IrH/CmBaZt7P1R6j1Xdp58thIa6jm4Je7saGs+2AA== + version "3.0.6" + resolved "https://registry.yarnpkg.com/@csstools/postcss-ic-unit/-/postcss-ic-unit-3.0.6.tgz#441f18a9064884e1e6ab77169413e0e6184f5c1d" + integrity sha512-fHaU9C/sZPauXMrzPitZ/xbACbvxbkPpHoUgB9Kw5evtsBWdVkVrajOyiT9qX7/c+G1yjApoQjP1fQatldsy9w== dependencies: - "@csstools/postcss-progressive-custom-properties" "^3.1.0" + "@csstools/postcss-progressive-custom-properties" "^3.2.0" "@csstools/utilities" "^1.0.0" postcss-value-parser "^4.2.0" @@ -1217,11 +1226,11 @@ integrity sha512-wtb+IbUIrIf8CrN6MLQuFR7nlU5C7PwuebfeEXfjthUha1+XZj2RVi+5k/lukToA24sZkYAiSJfHM8uG/UZIdg== "@csstools/postcss-is-pseudo-class@^4.0.3": - version "4.0.5" - resolved "https://registry.yarnpkg.com/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-4.0.5.tgz#c2b9a89e8c2f4cb80c3587dae1ed544447bbd16e" - integrity sha512-qG3MI7IN3KY9UwdaE9E7G7sFydscVW7nAj5OGwaBP9tQPEEVdxXTGI+l1ZW5EUpZFSj+u3q/22fH5+8HI72+Bg== + version "4.0.6" + resolved "https://registry.yarnpkg.com/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-4.0.6.tgz#149b3bf9dde739932a545079da917ca25464cba0" + integrity sha512-HilOhAsMpFheMYkuaREZx+CGa4hsG6kQdzwXSsuqKDFzYz2eIMP213+3dH/vUbPXaWrzqLKr8m3i0dgYPoh7vg== dependencies: - "@csstools/selector-specificity" "^3.0.2" + "@csstools/selector-specificity" "^3.0.3" postcss-selector-parser "^6.0.13" "@csstools/postcss-logical-float-and-clear@^2.0.0": @@ -1247,31 +1256,31 @@ postcss-value-parser "^4.2.0" "@csstools/postcss-logical-viewport-units@^2.0.3": - version "2.0.6" - resolved "https://registry.yarnpkg.com/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-2.0.6.tgz#1f91e865e73f5d135038c519957a3b95ffe552ad" - integrity sha512-6hV0ngZh8J7HqNY3kyt+z5ABN/XE18qvrU7ne4YSkKfltrWDnQgGiW/Q+h7bdQz8/W5juAefcdCCAJUIBE7erg== + version "2.0.7" + resolved "https://registry.yarnpkg.com/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-2.0.7.tgz#3bb03b9a57fe9ec2304bc35cf6c3d5d7c938ee26" + integrity sha512-L4G3zsp/bnU0+WXUyysihCUH14LkfMgUJsS9vKz3vCYbVobOTqQRoNXnEPpyNp8WYyolLqAWbGGJhVu8J6u2OQ== dependencies: - "@csstools/css-tokenizer" "^2.2.3" + "@csstools/css-tokenizer" "^2.2.4" "@csstools/utilities" "^1.0.0" "@csstools/postcss-media-minmax@^1.1.0": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@csstools/postcss-media-minmax/-/postcss-media-minmax-1.1.3.tgz#87ff7af309916b36fe00e1f4ad6e03a5c16e74b9" - integrity sha512-W9AFRQSLvT+Dxtp20AewzGTUxzkJ21XSKzqRALwQdAv0uJGXkR76qgdhkoX0L/tcV4gXtgDfVtGYL/x2Nz/M5Q== + version "1.1.4" + resolved "https://registry.yarnpkg.com/@csstools/postcss-media-minmax/-/postcss-media-minmax-1.1.4.tgz#1af01cc02fdb936a1c10a11e2663fd1b1ce1bd79" + integrity sha512-xl/PIO3TUbXO1ZA4SA6HCw+Q9UGe2cgeRKx3lHCzoNig2D4bT5vfVCOrwhxjUb09oHihc9eI3I0iIfVPiXaN1A== dependencies: - "@csstools/css-calc" "^1.1.7" - "@csstools/css-parser-algorithms" "^2.6.0" - "@csstools/css-tokenizer" "^2.2.3" - "@csstools/media-query-list-parser" "^2.1.8" + "@csstools/css-calc" "^1.2.0" + "@csstools/css-parser-algorithms" "^2.6.1" + "@csstools/css-tokenizer" "^2.2.4" + "@csstools/media-query-list-parser" "^2.1.9" "@csstools/postcss-media-queries-aspect-ratio-number-values@^2.0.3": - version "2.0.6" - resolved "https://registry.yarnpkg.com/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-2.0.6.tgz#ca6dae6949bfb0f274a4029776614720e243acbe" - integrity sha512-awc2qenSDvx6r+w6G9xxENp+LsbvHC8mMMV23KYmk4pR3YL8JxeKPDSiDhmqd93FQ9nNNDc/CaCQEcvP+GV4rw== + version "2.0.7" + resolved "https://registry.yarnpkg.com/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-2.0.7.tgz#5f4939e6330a3c2cd0cba1e1b76bc51a74dc839c" + integrity sha512-HBDAQw1K0NilcHGMUHv8jzf2mpOtcWTVKtuY3AeZ5TS1uyWWNVi5/yuA/tREPLU9WifNdqHQ+rfbsV/8zTIkTg== dependencies: - "@csstools/css-parser-algorithms" "^2.6.0" - "@csstools/css-tokenizer" "^2.2.3" - "@csstools/media-query-list-parser" "^2.1.8" + "@csstools/css-parser-algorithms" "^2.6.1" + "@csstools/css-tokenizer" "^2.2.4" + "@csstools/media-query-list-parser" "^2.1.9" "@csstools/postcss-nested-calc@^3.0.0": version "3.0.2" @@ -1289,32 +1298,32 @@ postcss-value-parser "^4.2.0" "@csstools/postcss-oklab-function@^3.0.7": - version "3.0.10" - resolved "https://registry.yarnpkg.com/@csstools/postcss-oklab-function/-/postcss-oklab-function-3.0.10.tgz#9f230ce28a266de8a8e264025aebce41313d4053" - integrity sha512-s9trs1c+gUMtaTtwrrIpdVQkUbRuwi6bQ9rBHaqwt4kd3kEnEYfP85uLY1inFx6Rt8OM2XVg3PSYbfnFSAO51A== - dependencies: - "@csstools/css-color-parser" "^1.5.2" - "@csstools/css-parser-algorithms" "^2.6.0" - "@csstools/css-tokenizer" "^2.2.3" - "@csstools/postcss-progressive-custom-properties" "^3.1.0" + version "3.0.14" + resolved "https://registry.yarnpkg.com/@csstools/postcss-oklab-function/-/postcss-oklab-function-3.0.14.tgz#7d8b2e9c46c72f019962cfa375f46582c49281a5" + integrity sha512-92xdpcfc2wB3z4+GftPA0PXMuGI/tRLw9Tc0+HzpaAHHxyLK6aCJtoQIcw0Ox/PthXtqXZn/3wWT/Idfe8I7Wg== + dependencies: + "@csstools/css-color-parser" "^2.0.0" + "@csstools/css-parser-algorithms" "^2.6.1" + "@csstools/css-tokenizer" "^2.2.4" + "@csstools/postcss-progressive-custom-properties" "^3.2.0" "@csstools/utilities" "^1.0.0" -"@csstools/postcss-progressive-custom-properties@^3.0.2", "@csstools/postcss-progressive-custom-properties@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-3.1.0.tgz#e4d6143b3ba50d1f7435932fd112db31e18f05af" - integrity sha512-Mfb1T1BHa6pktLI+poMEHI7Q+VYvAsdwJZPFsSkIB2ZUsawCiPxXLw06BKSVPITxFlaY/FEUzfpyOTfX9YCE2w== +"@csstools/postcss-progressive-custom-properties@^3.0.2", "@csstools/postcss-progressive-custom-properties@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-3.2.0.tgz#811da8616938e8148a7c4fb40c26e30bf94d4ceb" + integrity sha512-BZlirVxCRgKlE7yVme+Xvif72eTn1MYXj8oZ4Knb+jwaH4u3AN1DjbhM7j86RP5vvuAOexJ4JwfifYYKWMN/QQ== dependencies: postcss-value-parser "^4.2.0" "@csstools/postcss-relative-color-syntax@^2.0.7": - version "2.0.10" - resolved "https://registry.yarnpkg.com/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-2.0.10.tgz#07b9484c841623e32777bd7becac7679ce62c08d" - integrity sha512-IkTIk9Eq2VegSN4lgsljGY8boyfX3l3Pw58e+R9oyPe/Ye7r3NwuiQ3w0nkXoQ+RC+d240V6n7eZme2mEPqQvg== + version "2.0.14" + resolved "https://registry.yarnpkg.com/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-2.0.14.tgz#a983c3c3d389905037776f36f7fb6611d4de6316" + integrity sha512-NlxgLjAjVCTUVGiWk8WNj3dKvux9eC6O5aLM3BmdA8UXEwBHYI9r4IqlanxG9PlcXnzhTUX6eZsqgmxwt4FPow== dependencies: - "@csstools/css-color-parser" "^1.5.2" - "@csstools/css-parser-algorithms" "^2.6.0" - "@csstools/css-tokenizer" "^2.2.3" - "@csstools/postcss-progressive-custom-properties" "^3.1.0" + "@csstools/css-color-parser" "^2.0.0" + "@csstools/css-parser-algorithms" "^2.6.1" + "@csstools/css-tokenizer" "^2.2.4" + "@csstools/postcss-progressive-custom-properties" "^3.2.0" "@csstools/utilities" "^1.0.0" "@csstools/postcss-scope-pseudo-class@^3.0.0": @@ -1325,60 +1334,55 @@ postcss-selector-parser "^6.0.13" "@csstools/postcss-stepped-value-functions@^3.0.2": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-3.0.5.tgz#857cf8eb6bb6ac2831cabe58c15604cfb95af1b2" - integrity sha512-B8K8RaTrYVZLxbNzVUvFO3SlCDJDaUTAO7KRth05fa7f01ufPvb6ztdBuxSoRwOtmNp8iROxPJHOemWo2kBBtA== + version "3.0.6" + resolved "https://registry.yarnpkg.com/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-3.0.6.tgz#8263ddafab483100e13d63929d43cd12fb14767f" + integrity sha512-rnyp8tWRuBXERTHVdB5hjUlif5dQgPcyN+BX55wUnYpZ3LN9QPfK2Z3/HUZymwyou8Gg6vhd6X2W+g1pLq1jYg== dependencies: - "@csstools/css-calc" "^1.1.7" - "@csstools/css-parser-algorithms" "^2.6.0" - "@csstools/css-tokenizer" "^2.2.3" + "@csstools/css-calc" "^1.2.0" + "@csstools/css-parser-algorithms" "^2.6.1" + "@csstools/css-tokenizer" "^2.2.4" "@csstools/postcss-text-decoration-shorthand@^3.0.3": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-3.0.4.tgz#b8c5216faa2c9d8a05b3f93da7b403dd5dd53a79" - integrity sha512-yUZmbnUemgQmja7SpOZeU45+P49wNEgQguRdyTktFkZsHf7Gof+ZIYfvF6Cm+LsU1PwSupy4yUeEKKjX5+k6cQ== + version "3.0.6" + resolved "https://registry.yarnpkg.com/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-3.0.6.tgz#108afc5a66b96db3d0cca4f5d9414559c6b7a0bf" + integrity sha512-Q8HEu4AEiwNVZBD6+DpQ8M9SajpMow4+WtmndWIAv8qxDtDYL4JK1xXWkhOGk28PrcJawOvkrEZ8Ri59UN1TJw== dependencies: - "@csstools/color-helpers" "^4.0.0" + "@csstools/color-helpers" "^4.2.0" postcss-value-parser "^4.2.0" "@csstools/postcss-trigonometric-functions@^3.0.2": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-3.0.5.tgz#bf9f061120bed802fe133188a94c82ba79c440d6" - integrity sha512-RhBfQ0TsBudyPuoo8pXKdfQuUiQxMU/Sc5GyV57bWk93JbUHXq6b4CdPx+B/tHUeFKvocVJn/e2jbu96rh0d3Q== + version "3.0.6" + resolved "https://registry.yarnpkg.com/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-3.0.6.tgz#f8227f1807d28e817e4ff9053093eb8f1bcd9e13" + integrity sha512-i5Zd0bMJooZAn+ZcDmPij2WCkcOJJJ6opzK+QeDjxbMrYmoGQl0CY8FDHdeQyBF1Nly+Q0Fq3S7QfdNLKBBaCg== dependencies: - "@csstools/css-calc" "^1.1.7" - "@csstools/css-parser-algorithms" "^2.6.0" - "@csstools/css-tokenizer" "^2.2.3" + "@csstools/css-calc" "^1.2.0" + "@csstools/css-parser-algorithms" "^2.6.1" + "@csstools/css-tokenizer" "^2.2.4" "@csstools/postcss-unset-value@^3.0.0": version "3.0.1" resolved "https://registry.yarnpkg.com/@csstools/postcss-unset-value/-/postcss-unset-value-3.0.1.tgz#598a25630fd9ab0edf066d235916f7441404942a" integrity sha512-dbDnZ2ja2U8mbPP0Hvmt2RMEGBiF1H7oY6HYSpjteXJGihYwgxgTr6KRbbJ/V6c+4wd51M+9980qG4gKVn5ttg== -"@csstools/selector-specificity@^3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-3.0.2.tgz#ea61ba7bb24be3502c6aaa3190ed231f4633a81e" - integrity sha512-RpHaZ1h9LE7aALeQXmXrJkRG84ZxIsctEN2biEUmFyKpzFM3zZ35eUMcIzZFsw/2olQE6v69+esEqU2f1MKycg== +"@csstools/selector-resolve-nested@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@csstools/selector-resolve-nested/-/selector-resolve-nested-1.1.0.tgz#d872f2da402d3ce8bd0cf16ea5f9fba76b18e430" + integrity sha512-uWvSaeRcHyeNenKg8tp17EVDRkpflmdyvbE0DHo6D/GdBb6PDnCYYU6gRpXhtICMGMcahQmj2zGxwFM/WC8hCg== + +"@csstools/selector-specificity@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-3.0.3.tgz#208a3929ee614967a1fc8cd6cb758d9fcbf0caae" + integrity sha512-KEPNw4+WW5AVEIyzC80rTbWEUatTW2lXpN8+8ILC8PiPeWPjwUzrPZDIOZ2wwqDmeqOYTdSGyL3+vE5GC3FB3Q== "@csstools/utilities@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@csstools/utilities/-/utilities-1.0.0.tgz#42f3c213f2fb929324d465684ab9f46a0febd4bb" integrity sha512-tAgvZQe/t2mlvpNosA4+CkMiZ2azISW5WPAcdSalZlEjQvUfghHxfQcrCiK/7/CrfAWVxyM88kGFYO82heIGDg== -"@cypress/listr-verbose-renderer@^0.4.1": - version "0.4.1" - resolved "https://registry.yarnpkg.com/@cypress/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz#a77492f4b11dcc7c446a34b3e28721afd33c642a" - integrity sha512-EDiBsVPWC27DDLEJCo+dpl9ODHhdrwU57ccr9tspwCdG2ni0QVkf6LF0FGbhfujcjPxnXLIwsaks4sOrwrA4Qw== - dependencies: - chalk "^1.1.3" - cli-cursor "^1.0.2" - date-fns "^1.27.2" - figures "^1.7.0" - -"@cypress/request@^2.88.5": - version "2.88.12" - resolved "https://registry.yarnpkg.com/@cypress/request/-/request-2.88.12.tgz#ba4911431738494a85e93fb04498cb38bc55d590" - integrity sha512-tOn+0mDZxASFM+cuAP9szGUGPI1HwWVSvdzm7V4cCsPdFTx6qMj29CwaQmRAMIEhORIUBFBsYROYJcveK4uOjA== +"@cypress/request@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@cypress/request/-/request-3.0.1.tgz#72d7d5425236a2413bd3d8bb66d02d9dc3168960" + integrity sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ== dependencies: aws-sign2 "~0.7.0" aws4 "^1.8.0" @@ -1393,7 +1397,7 @@ json-stringify-safe "~5.0.1" mime-types "~2.1.19" performance-now "^2.1.0" - qs "~6.10.3" + qs "6.10.4" safe-buffer "^5.1.2" tough-cookie "^4.1.3" tunnel-agent "^0.6.0" @@ -1435,9 +1439,9 @@ integrity sha512-jx8xIWe/Up4tpNuM02M+rbnLoxdngTGk3Y8LjJsLGXXcSoKd/+eZStZcAlIO/jwxyz/bhPZnpqPJZWAmhOofuA== "@electron/asar@^3.2.1": - version "3.2.8" - resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.2.8.tgz#2ea722f3452583dbd4ffdcc4b4f5dc903f1d8178" - integrity sha512-cmskk5M06ewHMZAplSiF4AlME3IrnnZhKnWbtwKVLRkdJkKyUVjMLhDIiPIx/+6zQWVlKX/LtmK9xDme7540Sg== + version "3.2.9" + resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.2.9.tgz#7b3a1fd677b485629f334dd80ced8c85353ba7e7" + integrity sha512-Vu2P3X2gcZ3MY9W7yH72X9+AMXwUQZEJBrsPIbX0JsdllLtoh62/Q8Wg370/DawIEVKOyfD6KtTLo645ezqxUA== dependencies: commander "^5.0.0" glob "^7.1.6" @@ -1467,9 +1471,9 @@ fs-extra "^9.0.1" "@electron/osx-sign@^1.0.4": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@electron/osx-sign/-/osx-sign-1.0.5.tgz#0af7149f2fce44d1a8215660fd25a9fb610454d8" - integrity sha512-k9ZzUQtamSoweGQDV2jILiRIHUu7lYlJ3c6IEmjv1hC17rclE+eb9U+f6UFlOOETo0JzY1HNlXy4YOlCvl+Lww== + version "1.2.0" + resolved "https://registry.yarnpkg.com/@electron/osx-sign/-/osx-sign-1.2.0.tgz#d1c83cac03e52f210858594eb011142a1ad0ae70" + integrity sha512-kOA3bAeDXFMj2JHj0R2fk/IT92qpu3tZHwM4l/PdksAuy7eA3/23QktCiAoQICwPdtxCYdt9ZLimKvnNyUpdSQ== dependencies: compare-version "^0.1.2" debug "^4.3.4" @@ -1591,9 +1595,9 @@ hoist-non-react-statics "^3.3.1" "@emotion/serialize@^1.1.2", "@emotion/serialize@^1.1.3": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.3.tgz#84b77bfcfe3b7bb47d326602f640ccfcacd5ffb0" - integrity sha512-iD4D6QVZFDhcbH0RAG1uVu1CwVLMWUkCvAqqlewO/rxf8+87yIBAlt4+AxMiiKPLs5hFc0owNk/sLLAOROw3cA== + version "1.1.4" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.4.tgz#fc8f6d80c492cfa08801d544a05331d1cc7cd451" + integrity sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ== dependencies: "@emotion/hash" "^0.9.1" "@emotion/memoize" "^0.8.1" @@ -1641,6 +1645,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz#d1bc06aedb6936b3b6d313bf809a5a40387d2b7f" integrity sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA== +"@esbuild/aix-ppc64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz#a70f4ac11c6a1dfc18b8bbb13284155d933b9537" + integrity sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g== + "@esbuild/android-arm64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622" @@ -1651,6 +1660,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz#7ad65a36cfdb7e0d429c353e00f680d737c2aed4" integrity sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA== +"@esbuild/android-arm64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz#db1c9202a5bc92ea04c7b6840f1bbe09ebf9e6b9" + integrity sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg== + "@esbuild/android-arm@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682" @@ -1661,6 +1675,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.12.tgz#b0c26536f37776162ca8bde25e42040c203f2824" integrity sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w== +"@esbuild/android-arm@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.20.2.tgz#3b488c49aee9d491c2c8f98a909b785870d6e995" + integrity sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w== + "@esbuild/android-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2" @@ -1671,6 +1690,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.12.tgz#cb13e2211282012194d89bf3bfe7721273473b3d" integrity sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew== +"@esbuild/android-x64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.20.2.tgz#3b1628029e5576249d2b2d766696e50768449f98" + integrity sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg== + "@esbuild/darwin-arm64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1" @@ -1681,6 +1705,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz#cbee41e988020d4b516e9d9e44dd29200996275e" integrity sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g== +"@esbuild/darwin-arm64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz#6e8517a045ddd86ae30c6608c8475ebc0c4000bb" + integrity sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA== + "@esbuild/darwin-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d" @@ -1691,6 +1720,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz#e37d9633246d52aecf491ee916ece709f9d5f4cd" integrity sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A== +"@esbuild/darwin-x64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz#90ed098e1f9dd8a9381695b207e1cff45540a0d0" + integrity sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA== + "@esbuild/freebsd-arm64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54" @@ -1701,6 +1735,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz#1ee4d8b682ed363b08af74d1ea2b2b4dbba76487" integrity sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA== +"@esbuild/freebsd-arm64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz#d71502d1ee89a1130327e890364666c760a2a911" + integrity sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw== + "@esbuild/freebsd-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e" @@ -1711,6 +1750,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz#37a693553d42ff77cd7126764b535fb6cc28a11c" integrity sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg== +"@esbuild/freebsd-x64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz#aa5ea58d9c1dd9af688b8b6f63ef0d3d60cea53c" + integrity sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw== + "@esbuild/linux-arm64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0" @@ -1721,6 +1765,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz#be9b145985ec6c57470e0e051d887b09dddb2d4b" integrity sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA== +"@esbuild/linux-arm64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz#055b63725df678379b0f6db9d0fa85463755b2e5" + integrity sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A== + "@esbuild/linux-arm@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0" @@ -1731,6 +1780,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz#207ecd982a8db95f7b5279207d0ff2331acf5eef" integrity sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w== +"@esbuild/linux-arm@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz#76b3b98cb1f87936fbc37f073efabad49dcd889c" + integrity sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg== + "@esbuild/linux-ia32@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7" @@ -1741,6 +1795,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz#d0d86b5ca1562523dc284a6723293a52d5860601" integrity sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA== +"@esbuild/linux-ia32@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz#c0e5e787c285264e5dfc7a79f04b8b4eefdad7fa" + integrity sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig== + "@esbuild/linux-loong64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d" @@ -1751,6 +1810,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz#9a37f87fec4b8408e682b528391fa22afd952299" integrity sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA== +"@esbuild/linux-loong64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz#a6184e62bd7cdc63e0c0448b83801001653219c5" + integrity sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ== + "@esbuild/linux-mips64el@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231" @@ -1761,6 +1825,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz#4ddebd4e6eeba20b509d8e74c8e30d8ace0b89ec" integrity sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w== +"@esbuild/linux-mips64el@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz#d08e39ce86f45ef8fc88549d29c62b8acf5649aa" + integrity sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA== + "@esbuild/linux-ppc64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb" @@ -1771,6 +1840,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz#adb67dadb73656849f63cd522f5ecb351dd8dee8" integrity sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg== +"@esbuild/linux-ppc64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz#8d252f0b7756ffd6d1cbde5ea67ff8fd20437f20" + integrity sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg== + "@esbuild/linux-riscv64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6" @@ -1781,6 +1855,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz#11bc0698bf0a2abf8727f1c7ace2112612c15adf" integrity sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg== +"@esbuild/linux-riscv64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz#19f6dcdb14409dae607f66ca1181dd4e9db81300" + integrity sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg== + "@esbuild/linux-s390x@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071" @@ -1791,6 +1870,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz#e86fb8ffba7c5c92ba91fc3b27ed5a70196c3cc8" integrity sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg== +"@esbuild/linux-s390x@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz#3c830c90f1a5d7dd1473d5595ea4ebb920988685" + integrity sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ== + "@esbuild/linux-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338" @@ -1801,6 +1885,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz#5f37cfdc705aea687dfe5dfbec086a05acfe9c78" integrity sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg== +"@esbuild/linux-x64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz#86eca35203afc0d9de0694c64ec0ab0a378f6fff" + integrity sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw== + "@esbuild/netbsd-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1" @@ -1811,6 +1900,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz#29da566a75324e0d0dd7e47519ba2f7ef168657b" integrity sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA== +"@esbuild/netbsd-x64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz#e771c8eb0e0f6e1877ffd4220036b98aed5915e6" + integrity sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ== + "@esbuild/openbsd-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae" @@ -1821,6 +1915,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz#306c0acbdb5a99c95be98bdd1d47c916e7dc3ff0" integrity sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw== +"@esbuild/openbsd-x64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz#9a795ae4b4e37e674f0f4d716f3e226dd7c39baf" + integrity sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ== + "@esbuild/sunos-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d" @@ -1831,6 +1930,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz#0933eaab9af8b9b2c930236f62aae3fc593faf30" integrity sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA== +"@esbuild/sunos-x64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz#7df23b61a497b8ac189def6e25a95673caedb03f" + integrity sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w== + "@esbuild/win32-arm64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9" @@ -1841,6 +1945,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz#773bdbaa1971b36db2f6560088639ccd1e6773ae" integrity sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A== +"@esbuild/win32-arm64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz#f1ae5abf9ca052ae11c1bc806fb4c0f519bacf90" + integrity sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ== + "@esbuild/win32-ia32@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102" @@ -1851,6 +1960,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz#000516cad06354cc84a73f0943a4aa690ef6fd67" integrity sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ== +"@esbuild/win32-ia32@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz#241fe62c34d8e8461cd708277813e1d0ba55ce23" + integrity sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ== + "@esbuild/win32-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d" @@ -1861,6 +1975,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz#c57c8afbb4054a3ab8317591a0b7320360b444ae" integrity sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA== +"@esbuild/win32-x64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz#9c907b21e30a52db959ba4f80bb01a0cc403d5cc" + integrity sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ== + "@eslint-community/eslint-utils@^4.1.2", "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -2009,9 +2128,9 @@ integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== "@humanwhocodes/object-schema@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" - integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== "@hutson/parse-repository-url@^3.0.0": version "3.0.2" @@ -2023,10 +2142,10 @@ resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8" integrity sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw== -"@interactjs/types@1.10.26": - version "1.10.26" - resolved "https://registry.yarnpkg.com/@interactjs/types/-/types-1.10.26.tgz#5a6c0ef1dda9763515ff1192a40ecc99101c7a48" - integrity sha512-DekYpdkMV3XJVd/0k3f4pJluZAsCiG86yEtVXvGLK0lS/Fj0+OzYEv7HoMpcBZSkQ8s7//yaeEBgnxy2tV81lA== +"@interactjs/types@1.10.27": + version "1.10.27" + resolved "https://registry.yarnpkg.com/@interactjs/types/-/types-1.10.27.tgz#10afd71cef2498e2b5192cf0d46f937d8ceb767f" + integrity sha512-BUdv0cvs4H5ODuwft2Xp4eL8Vmi3LcihK42z0Ft/FbVJZoRioBsxH+LlsBdK4tAie7PqlKGy+1oyOncu1nQ6eA== "@isaacs/cliui@^8.0.2": version "8.0.2" @@ -2106,7 +2225,7 @@ magic-string "^0.27.0" react-docgen-typescript "^2.2.2" -"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2", "@jridgewell/gen-mapping@^0.3.5": +"@jridgewell/gen-mapping@^0.3.5": version "0.3.5" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== @@ -2126,19 +2245,19 @@ integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== "@jridgewell/source-map@^0.3.3": - version "0.3.5" - resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.5.tgz#a3bb4d5c6825aab0d281268f47f6ad5853431e91" - integrity sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ== + version "0.3.6" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a" + integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ== dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15": version "1.4.15" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.9": +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== @@ -2187,13 +2306,6 @@ lodash "^4.17.15" tmp-promise "^3.0.2" -"@mapbox/hast-util-table-cell-style@^0.1.3": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@mapbox/hast-util-table-cell-style/-/hast-util-table-cell-style-0.1.3.tgz#5b7166ae01297d72216932b245e4b2f0b642dca6" - integrity sha512-QsEsh5YaDvHoMQ2YHdvZy2iDnU3GgKVBTcHf6cILyoWDZtPSdlG444pL/ioPYO/GpXSfODBb9sefEetfC4v9oA== - dependencies: - unist-util-visit "^1.3.0" - "@mdx-js/react@^2.1.5": version "2.3.0" resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-2.3.0.tgz#4208bd6d70f0d0831def28ef28c26149b03180b3" @@ -2413,6 +2525,7 @@ react-hook-form "7.50.1" react-i18next "13.5.0" react-intersection-observer "^8.33.1" + react-markdown "9.0.1" react-redux "8.1.2" react-router-dom "5.3.4" react-select "5.4.0" @@ -2421,8 +2534,6 @@ redux "4.0.5" redux-observable "1.1.0" redux-thunk "2.3.0" - remark "9.0.0" - remark-react "4.0.3" reselect "4.0.0" rxjs "^6.5.1" semver "5.5.0" @@ -2928,77 +3039,85 @@ estree-walker "^2.0.2" picomatch "^2.3.1" -"@rollup/rollup-android-arm-eabi@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.0.tgz#38c3abd1955a3c21d492af6b1a1dca4bb1d894d6" - integrity sha512-+ac02NL/2TCKRrJu2wffk1kZ+RyqxVUlbjSagNgPm94frxtr+XDL12E5Ll1enWskLrtrZ2r8L3wED1orIibV/w== - -"@rollup/rollup-android-arm64@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.12.0.tgz#3822e929f415627609e53b11cec9a4be806de0e2" - integrity sha512-OBqcX2BMe6nvjQ0Nyp7cC90cnumt8PXmO7Dp3gfAju/6YwG0Tj74z1vKrfRz7qAv23nBcYM8BCbhrsWqO7PzQQ== - -"@rollup/rollup-darwin-arm64@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.12.0.tgz#6c082de71f481f57df6cfa3701ab2a7afde96f69" - integrity sha512-X64tZd8dRE/QTrBIEs63kaOBG0b5GVEd3ccoLtyf6IdXtHdh8h+I56C2yC3PtC9Ucnv0CpNFJLqKFVgCYe0lOQ== - -"@rollup/rollup-darwin-x64@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.12.0.tgz#c34ca0d31f3c46a22c9afa0e944403eea0edcfd8" - integrity sha512-cc71KUZoVbUJmGP2cOuiZ9HSOP14AzBAThn3OU+9LcA1+IUqswJyR1cAJj3Mg55HbjZP6OLAIscbQsQLrpgTOg== - -"@rollup/rollup-linux-arm-gnueabihf@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.12.0.tgz#48e899c1e438629c072889b824a98787a7c2362d" - integrity sha512-a6w/Y3hyyO6GlpKL2xJ4IOh/7d+APaqLYdMf86xnczU3nurFTaVN9s9jOXQg97BE4nYm/7Ga51rjec5nfRdrvA== - -"@rollup/rollup-linux-arm64-gnu@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.12.0.tgz#788c2698a119dc229062d40da6ada8a090a73a68" - integrity sha512-0fZBq27b+D7Ar5CQMofVN8sggOVhEtzFUwOwPppQt0k+VR+7UHMZZY4y+64WJ06XOhBTKXtQB/Sv0NwQMXyNAA== - -"@rollup/rollup-linux-arm64-musl@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.12.0.tgz#3882a4e3a564af9e55804beeb67076857b035ab7" - integrity sha512-eTvzUS3hhhlgeAv6bfigekzWZjaEX9xP9HhxB0Dvrdbkk5w/b+1Sxct2ZuDxNJKzsRStSq1EaEkVSEe7A7ipgQ== - -"@rollup/rollup-linux-riscv64-gnu@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.12.0.tgz#0c6ad792e1195c12bfae634425a3d2aa0fe93ab7" - integrity sha512-ix+qAB9qmrCRiaO71VFfY8rkiAZJL8zQRXveS27HS+pKdjwUfEhqo2+YF2oI+H/22Xsiski+qqwIBxVewLK7sw== - -"@rollup/rollup-linux-x64-gnu@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.12.0.tgz#9d62485ea0f18d8674033b57aa14fb758f6ec6e3" - integrity sha512-TenQhZVOtw/3qKOPa7d+QgkeM6xY0LtwzR8OplmyL5LrgTWIXpTQg2Q2ycBf8jm+SFW2Wt/DTn1gf7nFp3ssVA== - -"@rollup/rollup-linux-x64-musl@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.12.0.tgz#50e8167e28b33c977c1f813def2b2074d1435e05" - integrity sha512-LfFdRhNnW0zdMvdCb5FNuWlls2WbbSridJvxOvYWgSBOYZtgBfW9UGNJG//rwMqTX1xQE9BAodvMH9tAusKDUw== - -"@rollup/rollup-win32-arm64-msvc@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.12.0.tgz#68d233272a2004429124494121a42c4aebdc5b8e" - integrity sha512-JPDxovheWNp6d7AHCgsUlkuCKvtu3RB55iNEkaQcf0ttsDU/JZF+iQnYcQJSk/7PtT4mjjVG8N1kpwnI9SLYaw== - -"@rollup/rollup-win32-ia32-msvc@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.12.0.tgz#366ca62221d1689e3b55a03f4ae12ae9ba595d40" - integrity sha512-fjtuvMWRGJn1oZacG8IPnzIV6GF2/XG+h71FKn76OYFqySXInJtseAqdprVTDTyqPxQOG9Exak5/E9Z3+EJ8ZA== - -"@rollup/rollup-win32-x64-msvc@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.12.0.tgz#9ffdf9ed133a7464f4ae187eb9e1294413fab235" - integrity sha512-ZYmr5mS2wd4Dew/JjT0Fqi2NPB/ZhZ2VvPp7SmvPZb4Y1CG/LRcS6tcRo2cYU7zLK5A7cdbhWnnWmUjoI4qapg== - -"@samverschueren/stream-to-observable@^0.3.0": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.1.tgz#a21117b19ee9be70c379ec1877537ef2e1c63301" - integrity sha512-c/qwwcHyafOQuVQJj0IlBjf5yYgBI7YPJ77k4fOJYesb41jio65eaJODRUmfYKhTOFBrIZ66kgvGPlNbjuoRdQ== - dependencies: - any-observable "^0.3.0" +"@rollup/rollup-android-arm-eabi@4.16.2": + version "4.16.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.16.2.tgz#29b7b3c70ddf532fe6dcf859cbfc3e4714c34842" + integrity sha512-VGodkwtEuZ+ENPz/CpDSl091koMv8ao5jHVMbG1vNK+sbx/48/wVzP84M5xSfDAC69mAKKoEkSo+ym9bXYRK9w== + +"@rollup/rollup-android-arm64@4.16.2": + version "4.16.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.16.2.tgz#f50f65d0c3b8b30d070d8616b2dfc0978dd588bd" + integrity sha512-5/W1xyIdc7jw6c/f1KEtg1vYDBWnWCsLiipK41NiaWGLG93eH2edgE6EgQJ3AGiPERhiOLUqlDSfjRK08C9xFg== + +"@rollup/rollup-darwin-arm64@4.16.2": + version "4.16.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.16.2.tgz#be3d9fffbf6fc5b9d5f0642f1f0250e0ecab8d3e" + integrity sha512-vOAKMqZSTbPfyPVu1jBiy+YniIQd3MG7LUnqV0dA6Q5tyhdqYtxacTHP1+S/ksKl6qCtMG1qQ0grcIgk/19JEA== + +"@rollup/rollup-darwin-x64@4.16.2": + version "4.16.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.16.2.tgz#fe45a772526b2c03d545e20f97a1e5cd60a46e52" + integrity sha512-aIJVRUS3Dnj6MqocBMrcXlatKm64O3ITeQAdAxVSE9swyhNyV1dwnRgw7IGKIkDQofatd8UqMSyUxuFEa42EcA== + +"@rollup/rollup-linux-arm-gnueabihf@4.16.2": + version "4.16.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.16.2.tgz#450ecf66f30a51514413aafa79d28561db73151c" + integrity sha512-/bjfUiXwy3P5vYr6/ezv//Yle2Y0ak3a+Av/BKoi76nFryjWCkki8AuVoPR7ZU/ckcvAWFo77OnFK14B9B5JsA== + +"@rollup/rollup-linux-arm-musleabihf@4.16.2": + version "4.16.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.16.2.tgz#1e8807d220047084579cd01499c5476a325e0700" + integrity sha512-S24b+tJHwpq2TNRz9T+r71FjMvyBBApY8EkYxz8Cwi/rhH6h+lu/iDUxyc9PuHf9UvyeBFYkWWcrDahai/NCGw== + +"@rollup/rollup-linux-arm64-gnu@4.16.2": + version "4.16.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.16.2.tgz#128adb9dbf0057b989127d2e7fd73931a6729410" + integrity sha512-UN7VAXLyeyGbCQWiOtQN7BqmjTDw1ON2Oos4lfk0YR7yNhFEJWZiwGtvj9Ay4lsT/ueT04sh80Sg2MlWVVZ+Ug== + +"@rollup/rollup-linux-arm64-musl@4.16.2": + version "4.16.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.16.2.tgz#fddc7730045301a7fb0132532890e5edcb23d2bc" + integrity sha512-ZBKvz3+rIhQjusKMccuJiPsStCrPOtejCHxTe+yWp3tNnuPWtyCh9QLGPKz6bFNFbwbw28E2T6zDgzJZ05F1JQ== + +"@rollup/rollup-linux-powerpc64le-gnu@4.16.2": + version "4.16.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.16.2.tgz#7154fe9ffc6405b2a6555ca931c42c0aa5198c2a" + integrity sha512-LjMMFiVBRL3wOe095vHAekL4b7nQqf4KZEpdMWd3/W+nIy5o9q/8tlVKiqMbfieDypNXLsxM9fexOxd9Qcklyg== + +"@rollup/rollup-linux-riscv64-gnu@4.16.2": + version "4.16.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.16.2.tgz#7a7d091a94fa7c50ebf72d5578475093e01c739e" + integrity sha512-ohkPt0lKoCU0s4B6twro2aft+QROPdUiWwOjPNTzwTsBK5w+2+iT9kySdtOdq0gzWJAdiqsV4NFtXOwGZmIsHA== + +"@rollup/rollup-linux-s390x-gnu@4.16.2": + version "4.16.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.16.2.tgz#39b87bd355dfafbc062ca856d3d6bc5aa1905d89" + integrity sha512-jm2lvLc+/gqXfndlpDw05jKvsl/HKYxUEAt1h5UXcMFVpO4vGpoWmJVUfKDtTqSaHcCNw1his1XjkgR9aort3w== + +"@rollup/rollup-linux-x64-gnu@4.16.2": + version "4.16.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.16.2.tgz#30b88169db18dec202ab9662d5148523d59da553" + integrity sha512-oc5/SlITI/Vj/qL4UM+lXN7MERpiy1HEOnrE+SegXwzf7WP9bzmZd6+MDljCEZTdSY84CpvUv9Rq7bCaftn1+g== + +"@rollup/rollup-linux-x64-musl@4.16.2": + version "4.16.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.16.2.tgz#d4fd52a28d5ce4aaed436311d89a9a1eaff87c2d" + integrity sha512-/2VWEBG6mKbS2itm7hzPwhIPaxfZh/KLWrYg20pCRLHhNFtF+epLgcBtwy3m07bl/k86Q3PFRAf2cX+VbZbwzQ== + +"@rollup/rollup-win32-arm64-msvc@4.16.2": + version "4.16.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.16.2.tgz#edd352302e3fa6a2d612447590b0a0887cdbf762" + integrity sha512-Wg7ANh7+hSilF0lG3e/0Oy8GtfTIfEk1327Bw8juZOMOoKmJLs3R+a4JDa/4cHJp2Gs7QfCDTepXXcyFD0ubBg== + +"@rollup/rollup-win32-ia32-msvc@4.16.2": + version "4.16.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.16.2.tgz#f17cc1db108f364bf6ef427f98844b5f742d31f0" + integrity sha512-J/jCDKVMWp0Y2ELnTjpQFYUCUWv1Jr+LdFrJVZtdqGyjDo0PHPa7pCamjHvJel6zBFM3doFFqAr7cmXYWBAbfw== + +"@rollup/rollup-win32-x64-msvc@4.16.2": + version "4.16.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.16.2.tgz#98fb87589960075d39c44784e3a99f67138602f4" + integrity sha512-3nIf+SJMs2ZzrCh+SKNqgLVV9hS/UY0UjT1YU8XQYFGLiUfmHYJ/5trOU1XSvmHjV5gTF/K3DjrWxtyzKKcAHA== "@serialport/binding-mock@10.2.2": version "10.2.2" @@ -3514,9 +3633,9 @@ lodash "^4.17.15" "@storybook/csf@^0.1.2": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@storybook/csf/-/csf-0.1.2.tgz#8e7452f0097507f5841b5ade3f5da1525bc9afb2" - integrity sha512-ePrvE/pS1vsKR9Xr+o+YwdqNgHUyXvg+1Xjx0h9LrVx7Zq4zNe06pd63F5EvzTbCbJsHj7GHr9tkiaqm7U8WRA== + version "0.1.4" + resolved "https://registry.yarnpkg.com/@storybook/csf/-/csf-0.1.4.tgz#18224bcd571fa834ccc4bebda8a0ca4cedbc4d91" + integrity sha512-B9UI/lsQMjF+oEfZCI6YXNoeuBcGZoOP5x8yKbe2tIEmsMjSztFKkpPzi5nLCnBk/MBtl6QJeI3ksJnbsWPkOw== dependencies: type-fest "^2.19.0" @@ -3730,10 +3849,10 @@ lz-string "^1.5.0" pretty-format "^27.0.2" -"@testing-library/jest-dom@6.4.0": - version "6.4.0" - resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.4.0.tgz#e7391967af57273effdaa181fc291be0ecc155bd" - integrity sha512-GgGT3OR8qhIjk2SBMy51AYDWoMnAyR/cwjZO4SttuBmIQ9wWy9QmVOeaSbgT5Bm0J6qLBaf4+dsJWfisvafoaA== +"@testing-library/jest-dom@6.4.2": + version "6.4.2" + resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.4.2.tgz#38949f6b63722900e2d75ba3c6d9bf8cffb3300e" + integrity sha512-CzqH0AFymEMG48CpzXFriYYkOjk6ZGPCLMhW9e9jg3KMCn5OfJecF8GtGW7yGfR/IgCe3SX8BSwjdzI6BBbZLw== dependencies: "@adobe/css-tools" "^4.3.2" "@babel/runtime" "^7.9.2" @@ -3873,7 +3992,7 @@ resolved "https://registry.yarnpkg.com/@types/dateformat/-/dateformat-3.0.1.tgz#98d747a2e5e9a56070c6bf14e27bff56204e34cc" integrity sha512-KlPPdikagvL6ELjWsljbyDIPzNCeliYkqRpI+zea99vBBbCIA5JNshZAwQKTON139c87y9qvTFVgkFd14rtS4g== -"@types/debug@^4.1.6": +"@types/debug@^4.0.0", "@types/debug@^4.1.6": version "4.1.12" resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917" integrity sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ== @@ -3910,6 +4029,13 @@ resolved "https://registry.yarnpkg.com/@types/escodegen/-/escodegen-0.0.6.tgz#5230a9ce796e042cda6f086dbf19f22ea330659c" integrity sha512-AjwI4MvWx3HAOaZqYsjKWyEObT9lcVV0Y0V8nXo6cXzN8ZiMxVhf6F3d/UNvXVGKrEzL/Dluc5p+y9GkzlTWig== +"@types/estree-jsx@^1.0.0": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree-jsx/-/estree-jsx-1.0.5.tgz#858a88ea20f34fe65111f005a689fa1ebf70dc18" + integrity sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg== + dependencies: + "@types/estree" "*" + "@types/estree@*", "@types/estree@1.0.5", "@types/estree@^1.0.0": version "1.0.5" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" @@ -3926,9 +4052,9 @@ integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== "@types/express-serve-static-core@^4.17.33": - version "4.17.43" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz#10d8444be560cb789c4735aea5eac6e5af45df54" - integrity sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg== + version "4.19.0" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz#3ae8ab3767d98d0b682cda063c3339e1e86ccfaa" + integrity sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ== dependencies: "@types/node" "*" "@types/qs" "*" @@ -3985,6 +4111,13 @@ dependencies: "@types/node" "*" +"@types/hast@^3.0.0": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-3.0.4.tgz#1d6b39993b82cea6ad783945b0508c25903e15aa" + integrity sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ== + dependencies: + "@types/unist" "*" + "@types/history@^4.7.11": version "4.7.11" resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64" @@ -4052,25 +4185,27 @@ "@types/node" "*" "@types/lodash@^4.14.165", "@types/lodash@^4.14.167", "@types/lodash@^4.14.191": - version "4.14.202" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.202.tgz#f09dbd2fb082d507178b2f2a5c7e74bd72ff98f8" - integrity sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ== + version "4.17.0" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.0.tgz#d774355e41f372d5350a4d0714abb48194a489c3" + integrity sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA== + +"@types/mdast@^4.0.0": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-4.0.3.tgz#1e011ff013566e919a4232d1701ad30d70cab333" + integrity sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg== + dependencies: + "@types/unist" "*" "@types/mdx@^2.0.0": - version "2.0.11" - resolved "https://registry.yarnpkg.com/@types/mdx/-/mdx-2.0.11.tgz#21f4c166ed0e0a3a733869ba04cd8daea9834b8e" - integrity sha512-HM5bwOaIQJIQbAYfax35HCKxx7a3KrK3nBtIqJgSOitivTD1y3oW9P3rxY9RkXYPUk7y/AjAohfHKmFpGE79zw== + version "2.0.13" + resolved "https://registry.yarnpkg.com/@types/mdx/-/mdx-2.0.13.tgz#68f6877043d377092890ff5b298152b0a21671bd" + integrity sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw== "@types/mime-types@^2.1.0": version "2.1.4" resolved "https://registry.yarnpkg.com/@types/mime-types/-/mime-types-2.1.4.tgz#93a1933e24fed4fb9e4adc5963a63efcbb3317a2" integrity sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w== -"@types/mime@*": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.4.tgz#2198ac274de6017b44d941e00261d5bc6a0e0a45" - integrity sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw== - "@types/mime@^1": version "1.3.5" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" @@ -4117,21 +4252,16 @@ form-data "^4.0.0" "@types/node@*": - version "20.11.24" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.24.tgz#cc207511104694e84e9fb17f9a0c4c42d4517792" - integrity sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long== + version "20.12.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.7.tgz#04080362fa3dd6c5822061aa3124f5c152cff384" + integrity sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg== dependencies: undici-types "~5.26.4" -"@types/node@12.12.50": - version "12.12.50" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.50.tgz#e9b2e85fafc15f2a8aa8fdd41091b983da5fd6ee" - integrity sha512-5ImO01Fb8YsEOYpV+aeyGYztcYcjGsBvN4D7G5r1ef2cuQOpymjWNQi5V0rKHE6PC2ru3HkoUr/Br2/8GUA84w== - "@types/node@^18.0.0", "@types/node@^18.11.18": - version "18.19.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.21.tgz#f4ca1ac8ffb05ee4b89163c2d6fac9a1a59ee149" - integrity sha512-2Q2NeB6BmiTFQi4DHBzncSoq/cJMLDdhPaAoJFnFCyD9a8VPZRf7a1GAwp1Edb7ROaZc5Jz/tnZyL6EsWMRaqw== + version "18.19.31" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.31.tgz#b7d4a00f7cb826b60a543cebdbda5d189aaecdcd" + integrity sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA== dependencies: undici-types "~5.26.4" @@ -4159,9 +4289,9 @@ integrity sha512-nj39q0wAIdhwn7DGUyT9irmsKK1tV0bd5WFEhgpqNTMFZ8cE+jieuTphCW0tfdm47S2zVT5mr09B28b1chmQMA== "@types/prop-types@*": - version "15.7.11" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.11.tgz#2596fb352ee96a1379c657734d4b913a613ad563" - integrity sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng== + version "15.7.12" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6" + integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== "@types/pump@^1.1.0": version "1.1.3" @@ -4176,9 +4306,9 @@ integrity sha512-hroOstUScF6zhIi+5+x0dzqrHA1EJi+Irri6b1fxolMTqqHIV/Cg77EtnQcZqZCu8hR3mX2BzIxN4/GzI68Kfw== "@types/qs@*", "@types/qs@^6.9.5": - version "6.9.12" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.12.tgz#afa96b383a3a6fdc859453a1892d41b607fc7756" - integrity sha512-bZcOkJ6uWrL0Qb2NAWKa7TBU+mJHPzhx9jjLL1KHF+XpzEcR7EXHvjbHlGtR/IsP1vyPrehuS6XqkmaePy//mg== + version "6.9.15" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.15.tgz#adde8a060ec9c305a82de1babc1056e73bd64dce" + integrity sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg== "@types/query-string@6.2.0": version "6.2.0" @@ -4206,9 +4336,9 @@ "@types/react" "*" "@types/react-dom@^18.0.0": - version "18.2.19" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.19.tgz#b84b7c30c635a6c26c6a6dfbb599b2da9788be58" - integrity sha512-aZvQL6uUbIJpjZk4U8JZGbau9KDeAwMfmhyWorxgBkqDIEf6ROjRozcmPIicqsUwPUjbkDfHKgGee1Lq65APcA== + version "18.2.25" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.25.tgz#2946a30081f53e7c8d585eb138277245caedc521" + integrity sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA== dependencies: "@types/react" "*" @@ -4247,12 +4377,11 @@ "@types/react" "*" "@types/react@*", "@types/react@>=16": - version "18.2.62" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.62.tgz#2527a7a54749b1a99c87a4aa8b83e26846face38" - integrity sha512-l3f57BbaEKP0xcFzf+5qRG8/PXykZiuVM6eEoPtqBPCp6dxO3HhDkLIgIyXPhPKNAeXn3KO2pEaNgzaEo/asaw== + version "18.2.79" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.79.tgz#c40efb4f255711f554d47b449f796d1c7756d865" + integrity sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w== dependencies: "@types/prop-types" "*" - "@types/scheduler" "*" csstype "^3.0.2" "@types/react@18.2.51": @@ -4303,9 +4432,9 @@ "@types/node" "*" "@types/scheduler@*": - version "0.16.8" - resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.8.tgz#ce5ace04cfeabe7ef87c0091e50752e36707deff" - integrity sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A== + version "0.23.0" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.23.0.tgz#0a6655b3e2708eaabca00b7372fafd7a792a7b09" + integrity sha512-YIoDCTH3Af6XM5VuwGG/QL/CJqga1Zm3NkU3HZ4ZHK2fRMPYP1VczsTUqtsf43PH/iJNVlPHAo2oWX7BSdB2Hw== "@types/semver@^6.0.1": version "6.2.7" @@ -4326,18 +4455,18 @@ "@types/node" "*" "@types/serve-static@*": - version "1.15.5" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.5.tgz#15e67500ec40789a1e8c9defc2d32a896f05b033" - integrity sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ== + version "1.15.7" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714" + integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw== dependencies: "@types/http-errors" "*" - "@types/mime" "*" "@types/node" "*" + "@types/send" "*" -"@types/sinonjs__fake-timers@^6.0.1": - version "6.0.4" - resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.4.tgz#0ecc1b9259b76598ef01942f547904ce61a6a77d" - integrity sha512-IFQTJARgMUBF+xVd2b+hIgXWrZEjND3vJtRCvIelcFB5SIXfjV4bOHbHJ0eXKh+0COrBRc8MqteKAz/j88rE0A== +"@types/sinonjs__fake-timers@8.1.1": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz#b49c2c70150141a15e0fa7e79cf1f92a72934ce3" + integrity sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g== "@types/sizzle@^2.3.2": version "2.3.8" @@ -4394,9 +4523,9 @@ integrity sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA== "@types/verror@^1.10.3": - version "1.10.9" - resolved "https://registry.yarnpkg.com/@types/verror/-/verror-1.10.9.tgz#420c32adb9a2dd50b3db4c8f96501e05a0e72941" - integrity sha512-MLx9Z+9lGzwEuW16ubGeNkpBDE84RpB/NyGgg6z2BTpWzKkGU451cAY3UkUzZEp72RHF585oJ3V8JVNqIplcAQ== + version "1.10.10" + resolved "https://registry.yarnpkg.com/@types/verror/-/verror-1.10.10.tgz#d5a4b56abac169bfbc8b23d291363a682e6fa087" + integrity sha512-l4MM0Jppn18hb9xmM6wwD1uTdShpf9Pn80aXTStnK1C94gtPvJcV2FrDmbOQUAQfJ1cKZHktkQUDwEqaAKXMMg== "@types/vfile-message@*": version "2.0.0" @@ -4595,7 +4724,7 @@ "@typescript-eslint/types" "6.21.0" eslint-visitor-keys "^3.4.1" -"@ungap/structured-clone@^1.2.0": +"@ungap/structured-clone@^1.0.0", "@ungap/structured-clone@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== @@ -5040,10 +5169,17 @@ ansi-colors@^3.0.0: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== -ansi-escapes@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== +ansi-colors@^4.1.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + +ansi-escapes@^4.3.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" ansi-html-community@0.0.8: version "0.0.8" @@ -5055,11 +5191,6 @@ ansi-regex@^2.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== -ansi-regex@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" - integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== - ansi-regex@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" @@ -5104,11 +5235,6 @@ ansi-styles@^6.1.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== -any-observable@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b" - integrity sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog== - anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" @@ -5194,7 +5320,7 @@ aproba@^1.1.1: resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== -arch@^2.1.2: +arch@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== @@ -5227,9 +5353,9 @@ argparse@^2.0.1: integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== aria-hidden@^1.1.1: - version "1.2.3" - resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.3.tgz#14aeb7fb692bbb72d69bebfa47279c1fd725e954" - integrity sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ== + version "1.2.4" + resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.4.tgz#b78e383fdbc04d05762c78b4a25a501e736c4522" + integrity sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A== dependencies: tslib "^2.0.0" @@ -5291,14 +5417,15 @@ array-ify@^1.0.0: integrity sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng== array-includes@^3.1.6, array-includes@^3.1.7: - version "3.1.7" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" - integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== + version "3.1.8" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" + integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" is-string "^1.0.7" array-union@^1.0.1, array-union@^1.0.2: @@ -5323,37 +5450,28 @@ array-unique@^0.3.2: resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ== -array.prototype.filter@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array.prototype.filter/-/array.prototype.filter-1.0.3.tgz#423771edeb417ff5914111fff4277ea0624c0d0e" - integrity sha512-VizNcj/RGJiUyQBgzwxzE5oHdeuXY5hSbbmKMlphj1cy1Vl7Pn2asCGbSrru6hSQjmCzqTBPVWAF/whmEOVHbw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-array-method-boxes-properly "^1.0.0" - is-string "^1.0.7" - array.prototype.findlast@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.4.tgz#eeb9e45fc894055c82e5675c463e8077b827ad36" - integrity sha512-BMtLxpV+8BD+6ZPFIWmnUBpQoy+A+ujcg4rhp2iwCRJYA7PEh2MS4NL3lz8EiDlLrJPp2hg9qWihr5pd//jcGw== + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz#3e4fbcb30a15a7f5bf64cf2faae22d139c2e4904" + integrity sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ== dependencies: - call-bind "^1.0.5" + call-bind "^1.0.7" define-properties "^1.2.1" - es-abstract "^1.22.3" + es-abstract "^1.23.2" es-errors "^1.3.0" + es-object-atoms "^1.0.0" es-shim-unscopables "^1.0.2" array.prototype.findlastindex@^1.2.3: - version "1.2.4" - resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.4.tgz#d1c50f0b3a9da191981ff8942a0aedd82794404f" - integrity sha512-hzvSHUshSpCflDR1QMUBLHGHP1VIEBegT4pix9H/Z92Xw3ySoy6c2qh7lJWTJnRJ8JCZ9bJNCgTyYaJGcJu6xQ== + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d" + integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ== dependencies: - call-bind "^1.0.5" + call-bind "^1.0.7" define-properties "^1.2.1" - es-abstract "^1.22.3" + es-abstract "^1.23.2" es-errors "^1.3.0" + es-object-atoms "^1.0.0" es-shim-unscopables "^1.0.2" array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.2: @@ -5377,14 +5495,16 @@ array.prototype.flatmap@^1.3.2: es-shim-unscopables "^1.0.0" array.prototype.reduce@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/array.prototype.reduce/-/array.prototype.reduce-1.0.6.tgz#63149931808c5fc1e1354814923d92d45f7d96d5" - integrity sha512-UW+Mz8LG/sPSU8jRDCjVr6J/ZKAGpHfwrZ6kWTG5qCxIEiXdVshqGnu5vEZA8S1y6X4aCSbQZ0/EEsfvEvBiSg== + version "1.0.7" + resolved "https://registry.yarnpkg.com/array.prototype.reduce/-/array.prototype.reduce-1.0.7.tgz#6aadc2f995af29cb887eb866d981dc85ab6f7dc7" + integrity sha512-mzmiUCVwtiD4lgxYP8g7IYy8El8p2CSMePvIbTS7gchKir/L1fgJrk0yDKmAX6mnRQFKNADYIk8nNlTris5H1Q== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" es-array-method-boxes-properly "^1.0.0" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" is-string "^1.0.7" array.prototype.toreversed@^1.1.2: @@ -5432,15 +5552,14 @@ asap@~2.0.3: resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== -asn1.js@^5.2.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" - integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== +asn1.js@^4.10.1: + version "4.10.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== dependencies: bn.js "^4.0.0" inherits "^2.0.1" minimalistic-assert "^1.0.0" - safer-buffer "^2.1.0" asn1@~0.2.3: version "0.2.6" @@ -5537,13 +5656,6 @@ async@^3.2.0, async@^3.2.2, async@^3.2.3: resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66" integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== -asynciterator.prototype@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz#8c5df0514936cdd133604dfcc9d3fb93f09b2b62" - integrity sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg== - dependencies: - has-symbols "^1.0.3" - asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -5560,12 +5672,12 @@ atob@^2.1.2: integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== autoprefixer@^10.0.2, autoprefixer@^10.4, autoprefixer@^10.4.16: - version "10.4.18" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.18.tgz#fcb171a3b017be7cb5d8b7a825f5aacbf2045163" - integrity sha512-1DKbDfsr6KUElM6wg+0zRNkB/Q7WcKYAaK+pzXn+Xqmszm/5Xa9coeNdtP88Vi+dPzZnMjhge8GIV49ZQkDa+g== + version "10.4.19" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.19.tgz#ad25a856e82ee9d7898c59583c1afeb3fa65f89f" + integrity sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew== dependencies: browserslist "^4.23.0" - caniuse-lite "^1.0.30001591" + caniuse-lite "^1.0.30001599" fraction.js "^4.3.7" normalize-range "^0.1.2" picocolors "^1.0.0" @@ -5584,7 +5696,7 @@ autoprefixer@^9.5.1: postcss "^7.0.32" postcss-value-parser "^4.1.0" -available-typed-arrays@^1.0.6, available-typed-arrays@^1.0.7: +available-typed-arrays@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== @@ -5592,9 +5704,9 @@ available-typed-arrays@^1.0.6, available-typed-arrays@^1.0.7: possible-typed-array-names "^1.0.0" aws-sdk@^2.264.1, aws-sdk@^2.493.0: - version "2.1569.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1569.0.tgz#b7568698ae4172be543536cfb9399361ac9955d0" - integrity sha512-9puKjesHKOjAYPqFurW/9nv3qhQ+STu3bVa5PN158SCeZPE6NsxZIWnHLglJvKU7N8UXJo1aJHmKDUGrsS7rXw== + version "2.1604.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1604.0.tgz#6b613adc6e06cc23e82e98d9f72d1df6d532ad3b" + integrity sha512-JSXNwKylbSZR2AL/jczOGJmPCZ/QpTys6SP89rhgy5LN677PJ6weQx5ShpPfGIcczGXjAeJDm8faWT53fYPCCw== dependencies: buffer "4.9.2" events "1.1.1" @@ -5659,29 +5771,29 @@ babel-plugin-macros@^3.1.0: cosmiconfig "^7.0.0" resolve "^1.19.0" -babel-plugin-polyfill-corejs2@^0.4.8: - version "0.4.8" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.8.tgz#dbcc3c8ca758a290d47c3c6a490d59429b0d2269" - integrity sha512-OtIuQfafSzpo/LhnJaykc0R/MMnuLSSVjVYy9mHArIZ9qTCSZ6TpWCuEKZYVoN//t8HqBNScHrOtCrIK5IaGLg== +babel-plugin-polyfill-corejs2@^0.4.10: + version "0.4.11" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz#30320dfe3ffe1a336c15afdcdafd6fd615b25e33" + integrity sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q== dependencies: "@babel/compat-data" "^7.22.6" - "@babel/helper-define-polyfill-provider" "^0.5.0" + "@babel/helper-define-polyfill-provider" "^0.6.2" semver "^6.3.1" -babel-plugin-polyfill-corejs3@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.9.0.tgz#9eea32349d94556c2ad3ab9b82ebb27d4bf04a81" - integrity sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg== +babel-plugin-polyfill-corejs3@^0.10.4: + version "0.10.4" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz#789ac82405ad664c20476d0233b485281deb9c77" + integrity sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg== dependencies: - "@babel/helper-define-polyfill-provider" "^0.5.0" - core-js-compat "^3.34.0" + "@babel/helper-define-polyfill-provider" "^0.6.1" + core-js-compat "^3.36.1" -babel-plugin-polyfill-regenerator@^0.5.5: - version "0.5.5" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz#8b0c8fc6434239e5d7b8a9d1f832bb2b0310f06a" - integrity sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg== +babel-plugin-polyfill-regenerator@^0.6.1: + version "0.6.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz#addc47e240edd1da1058ebda03021f382bba785e" + integrity sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg== dependencies: - "@babel/helper-define-polyfill-provider" "^0.5.0" + "@babel/helper-define-polyfill-provider" "^0.6.2" babel-plugin-styled-components@2.0.7: version "2.0.7" @@ -5728,6 +5840,11 @@ bail@^1.0.0: resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" integrity sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ== +bail@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/bail/-/bail-2.0.2.tgz#d26f5cd8fe5d6f832a31517b9f7c356040ba6d5d" + integrity sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw== + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -5806,9 +5923,9 @@ binary-extensions@^1.0.0: integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== bindings@^1.5.0: version "1.5.0" @@ -5834,7 +5951,7 @@ bl@^4.0.2, bl@^4.0.3, bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" -blob-util@2.0.2: +blob-util@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/blob-util/-/blob-util-2.0.2.tgz#3b4e3c281111bb7f11128518006cdc60b403a1eb" integrity sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ== @@ -6001,7 +6118,7 @@ browser-process-hrtime@^1.0.0: resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== -browserify-aes@^1.0.0, browserify-aes@^1.0.4: +browserify-aes@^1.0.4, browserify-aes@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== @@ -6041,18 +6158,19 @@ browserify-rsa@^4.0.0, browserify-rsa@^4.1.0: randombytes "^2.0.1" browserify-sign@^4.0.0: - version "4.2.2" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.2.tgz#e78d4b69816d6e3dd1c747e64e9947f9ad79bc7e" - integrity sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg== + version "4.2.3" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.3.tgz#7afe4c01ec7ee59a89a558a4b75bd85ae62d4208" + integrity sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw== dependencies: bn.js "^5.2.1" browserify-rsa "^4.1.0" create-hash "^1.2.0" create-hmac "^1.1.7" - elliptic "^6.5.4" + elliptic "^6.5.5" + hash-base "~3.0" inherits "^2.0.4" - parse-asn1 "^5.1.6" - readable-stream "^3.6.2" + parse-asn1 "^5.1.7" + readable-stream "^2.3.8" safe-buffer "^5.2.1" browserify-zlib@^0.1.4: @@ -6069,7 +6187,7 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.22.1, browserslist@^4.22.2, browserslist@^4.22.3, browserslist@^4.23.0: +browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.22.1, browserslist@^4.22.2, browserslist@^4.23.0: version "4.23.0" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab" integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== @@ -6138,7 +6256,7 @@ buffer@4.9.2, buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" -buffer@^5.1.0, buffer@^5.2.1, buffer@^5.5.0: +buffer@^5.1.0, buffer@^5.2.1, buffer@^5.5.0, buffer@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== @@ -6226,9 +6344,9 @@ builtin-status-codes@^3.0.0: integrity sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ== builtins@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.0.1.tgz#87f6db9ab0458be728564fa81d876d8d74552fa9" - integrity sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ== + version "5.1.0" + resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.1.0.tgz#6d85eeb360c4ebc166c3fdef922a15aa7316a5e8" + integrity sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg== dependencies: semver "^7.0.0" @@ -6466,10 +6584,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001587, caniuse-lite@^1.0.30001591: - version "1.0.30001593" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001593.tgz#7cda1d9e5b0cad6ebab4133b1f239d4ea44fe659" - integrity sha512-UWM1zlo3cZfkpBysd7AS+z+v007q9G1+fLTUU42rQnY6t2axoogPW/xol6T7juU5EUoOhML4WgBIdG+9yYqAjQ== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001587, caniuse-lite@^1.0.30001599: + version "1.0.30001612" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz#d34248b4ec1f117b70b24ad9ee04c90e0b8a14ae" + integrity sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g== caseless@~0.12.0: version "0.12.0" @@ -6481,6 +6599,11 @@ ccount@^1.0.0, ccount@^1.0.3: resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.1.0.tgz#246687debb6014735131be8abab2d93898f8d043" integrity sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg== +ccount@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5" + integrity sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg== + chai@^4.3.10: version "4.4.1" resolved "https://registry.yarnpkg.com/chai/-/chai-4.4.1.tgz#3603fa6eba35425b0f2ac91a009fe924106e50d1" @@ -6494,7 +6617,7 @@ chai@^4.3.10: pathval "^1.1.1" type-detect "^4.0.8" -chalk@^1.0.0, chalk@^1.1.3: +chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" integrity sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A== @@ -6535,21 +6658,41 @@ character-entities-html4@^1.0.0: resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-1.1.4.tgz#0e64b0a3753ddbf1fdc044c5fd01d0199a02e125" integrity sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g== +character-entities-html4@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-2.1.0.tgz#1f1adb940c971a4b22ba39ddca6b618dc6e56b2b" + integrity sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA== + character-entities-legacy@^1.0.0: version "1.1.4" resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== +character-entities-legacy@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz#76bc83a90738901d7bc223a9e93759fdd560125b" + integrity sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ== + character-entities@^1.0.0: version "1.2.4" resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== +character-entities@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.2.tgz#2d09c2e72cd9523076ccb21157dff66ad43fcc22" + integrity sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ== + character-reference-invalid@^1.0.0: version "1.1.4" resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== +character-reference-invalid@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz#85c66b041e43b47210faf401278abf808ac45cb9" + integrity sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw== + check-error@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" @@ -6638,11 +6781,6 @@ ci-info@^1.5.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A== -ci-info@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" - integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== - ci-info@^3.2.0: version "3.9.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" @@ -6656,7 +6794,7 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.1" safe-buffer "^5.0.1" -citty@^0.1.5, citty@^0.1.6: +citty@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/citty/-/citty-0.1.6.tgz#0f7904da1ed4625e1a9ea7e0fa780981aab7c5e4" integrity sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ== @@ -6697,20 +6835,6 @@ clean-stack@^2.0.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== -cli-cursor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" - integrity sha512-25tABq090YNKkF6JH7lcwO0zFJTRke4Jcq9iX2nr/Sz0Cjjv4gckmwlW6Ty/aoyFd6z3ysR2hMGC2GFugmBo6A== - dependencies: - restore-cursor "^1.0.1" - -cli-cursor@^2.0.0, cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw== - dependencies: - restore-cursor "^2.0.0" - cli-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" @@ -6723,23 +6847,15 @@ cli-spinners@^2.5.0: resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41" integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== -cli-table3@^0.6.1, cli-table3@~0.6.0: - version "0.6.3" - resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.3.tgz#61ab765aac156b52f222954ffc607a6f01dbeeb2" - integrity sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg== +cli-table3@^0.6.1, cli-table3@~0.6.1: + version "0.6.4" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.4.tgz#d1c536b8a3f2e7bec58f67ac9e5769b1b30088b0" + integrity sha512-Lm3L0p+/npIQWNIiyF/nAn7T5dnOwR3xNTHXYEBFBFVPXzCVNZ5lqEC/1eo/EVfpDsQ1I+TX4ORPQgp+UI0CRw== dependencies: string-width "^4.2.0" optionalDependencies: "@colors/colors" "1.5.0" -cli-truncate@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574" - integrity sha512-f4r4yJnbT++qUPI9NR4XLDLq41gQ+uqnPItWG0F5ZkehuNiTTa3EY0S4AqTSUOeJ7/zU41oWPQSNkW5BqPL9bg== - dependencies: - slice-ansi "0.0.4" - string-width "^1.0.1" - cli-truncate@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" @@ -6828,12 +6944,7 @@ coa@^2.0.2: chalk "^2.4.1" q "^1.1.2" -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA== - -collapse-white-space@^1.0.0, collapse-white-space@^1.0.2: +collapse-white-space@^1.0.2: version "1.0.6" resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287" integrity sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ== @@ -6891,6 +7002,11 @@ color@^3.0.0, color@^3.1.3: color-convert "^1.9.3" color-string "^1.6.0" +colorette@^2.0.16: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + colornames@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/colornames/-/colornames-1.1.1.tgz#f8889030685c7c4ff9e2a559f5077eb76a816f96" @@ -6921,6 +7037,11 @@ comma-separated-tokens@^1.0.0, comma-separated-tokens@^1.0.1: resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== +comma-separated-tokens@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz#4e89c9458acb61bc8fef19f4529973b2392839ee" + integrity sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg== + commander@2.17.x: version "2.17.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" @@ -7058,6 +7179,11 @@ conf@^6.2.1: semver "^6.2.0" write-file-atomic "^3.0.0" +confbox@^0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.7.tgz#ccfc0a2bcae36a84838e83a3b7f770fb17d6c579" + integrity sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA== + config-file-ts@^0.2.4: version "0.2.6" resolved "https://registry.yarnpkg.com/config-file-ts/-/config-file-ts-0.2.6.tgz#b424ff74612fb37f626d6528f08f92ddf5d22027" @@ -7293,10 +7419,10 @@ cookie@0.4.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== -cookie@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" - integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== +cookie@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" + integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== copy-concurrently@^1.0.0: version "1.0.5" @@ -7315,17 +7441,17 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw== -core-js-compat@^3.31.0, core-js-compat@^3.34.0: - version "3.36.0" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.36.0.tgz#087679119bc2fdbdefad0d45d8e5d307d45ba190" - integrity sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw== +core-js-compat@^3.31.0, core-js-compat@^3.36.1: + version "3.37.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.37.0.tgz#d9570e544163779bb4dff1031c7972f44918dc73" + integrity sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA== dependencies: - browserslist "^4.22.3" + browserslist "^4.23.0" core-js-pure@^3.30.2: - version "3.36.0" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.36.0.tgz#ffb34330b14e594d6a9835cf5843b4123f1d95db" - integrity sha512-cN28qmhRNgbMZZMc/RFu5w8pK9VJzpb2rJVR/lHuZJKwmXnoWOpXmMkxqBB514igkp1Hu8WGROsiOAzUcKdHOQ== + version "3.37.0" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.37.0.tgz#ce99fb4a7cec023fdbbe5b5bd1f06bbcba83316e" + integrity sha512-d3BrpyFr5eD4KcbRvQ3FTUx/KWmaDesr7+a3+1+P46IUnNoEt+oiLijPINZMEon7w9oGkIINWxrBAU9DEciwFQ== core-js@3.2.1: version "3.2.1" @@ -7343,9 +7469,9 @@ core-js@^2.4.0: integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== core-js@^3.6.4: - version "3.36.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.36.0.tgz#e752fa0b0b462a0787d56e9d73f80b0f7c0dde68" - integrity sha512-mt7+TUBbTFg5+GngsAxeKBTl5/VS0guFeJacYge9OmHb+m058UwwIm41SE9T4Den7ClatV57B6TYTuJ0CX1MAw== + version "3.37.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.37.0.tgz#d8dde58e91d156b2547c19d8a4efd5c7f6c426bb" + integrity sha512-fu5vHevQ8ZG4og+LXug8ulUtVxjOcEYvifJr7L5Bfq9GOztVqsKd9/59hUk2ZSbCrS3BqUr3EpaYGIYzq7g3Ug== core-util-is@1.0.2: version "1.0.2" @@ -7467,9 +7593,9 @@ crypto-random-string@^2.0.0: integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== css-blank-pseudo@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-6.0.1.tgz#f79f8b84cc00f891e16aa85f14093c5e1c3499a8" - integrity sha512-goSnEITByxTzU4Oh5oJZrEWudxTqk7L6IXj1UW69pO6Hv0UdX+Vsrt02FFu5DweRh2bLu6WpX/+zsQCu5O1gKw== + version "6.0.2" + resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-6.0.2.tgz#50db072d4fb5b40c2df9ffe5ca5fbb9b19c77fc8" + integrity sha512-J/6m+lsqpKPqWHOifAFtKFeGLOzw3jR92rxQcwRUfA/eTuZzKfKlxOmYDx2+tqOPQAueNvBiY8WhAeHu5qNmTg== dependencies: postcss-selector-parser "^6.0.13" @@ -7492,11 +7618,11 @@ css-declaration-sorter@^4.0.1: timsort "^0.3.0" css-has-pseudo@^6.0.0: - version "6.0.2" - resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-6.0.2.tgz#a1a15ee7082d72a23ed1d810220ba384da867d15" - integrity sha512-Z2Qm5yyOvJRTy6THdUlnGIX6PW/1wOc4FHWlfkcBkfkpZ3oz6lPdG+h+J7t1HZHT4uSSVR8XatXiMpqMUADXow== + version "6.0.3" + resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-6.0.3.tgz#babd8f208507d553b3986ee803b3adf4dd09c00e" + integrity sha512-qIsDxK/z0byH/mpNsv5hzQ5NOl8m1FRmOLgZpx4bG5uYHnOlO2XafeMI4mFIgNSViHwoUWcxSJZyyijaAmbs+A== dependencies: - "@csstools/selector-specificity" "^3.0.2" + "@csstools/selector-specificity" "^3.0.3" postcss-selector-parser "^6.0.13" postcss-value-parser "^4.2.0" @@ -7622,9 +7748,9 @@ css.escape@^1.5.1: integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg== cssdb@^7.9.0: - version "7.11.1" - resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-7.11.1.tgz#491841b281d337d7e5332e43b282429dd241b377" - integrity sha512-F0nEoX/Rv8ENTHsjMPGHd9opdjGfXkgRBafSUGnQKPzGZFB7Lm0BbT10x21TMOCrKLbVsJ0NoCDMk6AfKqw8/A== + version "7.11.2" + resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-7.11.2.tgz#127a2f5b946ee653361a5af5333ea85a39df5ae5" + integrity sha512-lhQ32TFkc1X4eTefGfYPvgovRSzIMofHkigfH8nWtyRL4XJLsRhJFreRvEgKzept7x1rjBuy3J/MurXLaFxW/A== cssesc@^3.0.0: version "3.0.0" @@ -7752,50 +7878,52 @@ cypress-file-upload@3.5.3: resolved "https://registry.yarnpkg.com/cypress-file-upload/-/cypress-file-upload-3.5.3.tgz#cd706485de3fb2cbd4a8c2dd90fe96d537bb4311" integrity sha512-S/czzqAj1BYz6Xxnfpx2aSc6hXsj76fd8/iuycJ2RxoxCcQMliw8eQV0ugzVlkzr1GD5dKGviNFGYqv3nRJ+Tg== -cypress@^6.6.0: - version "6.9.1" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-6.9.1.tgz#ce1106bfdc47f8d76381dba63f943447883f864c" - integrity sha512-/RVx6sOhsyTR9sd9v0BHI4tnDZAhsH9rNat7CIKCUEr5VPWxyfGH0EzK4IHhAqAH8vjFcD4U14tPiJXshoUrmQ== +cypress@13.7.1: + version "13.7.1" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-13.7.1.tgz#d1208eb04efd46ef52a30480a5da71a03373261a" + integrity sha512-4u/rpFNxOFCoFX/Z5h+uwlkBO4mWzAjveURi3vqdSu56HPvVdyGTxGw4XKGWt399Y1JwIn9E1L9uMXQpc0o55w== dependencies: - "@cypress/listr-verbose-renderer" "^0.4.1" - "@cypress/request" "^2.88.5" + "@cypress/request" "^3.0.0" "@cypress/xvfb" "^1.2.4" - "@types/node" "12.12.50" - "@types/sinonjs__fake-timers" "^6.0.1" + "@types/sinonjs__fake-timers" "8.1.1" "@types/sizzle" "^2.3.2" - arch "^2.1.2" - blob-util "2.0.2" + arch "^2.2.0" + blob-util "^2.0.2" bluebird "^3.7.2" + buffer "^5.7.1" cachedir "^2.3.0" chalk "^4.1.0" check-more-types "^2.24.0" - cli-table3 "~0.6.0" - commander "^5.1.0" + cli-cursor "^3.1.0" + cli-table3 "~0.6.1" + commander "^6.2.1" common-tags "^1.8.0" - dayjs "^1.9.3" - debug "4.3.2" - eventemitter2 "^6.4.2" - execa "^4.0.2" + dayjs "^1.10.4" + debug "^4.3.4" + enquirer "^2.3.6" + eventemitter2 "6.4.7" + execa "4.1.0" executable "^4.1.1" - extract-zip "^1.7.0" - fs-extra "^9.0.1" + extract-zip "2.0.1" + figures "^3.2.0" + fs-extra "^9.1.0" getos "^3.2.1" - is-ci "^2.0.0" - is-installed-globally "^0.3.2" + is-ci "^3.0.1" + is-installed-globally "~0.4.0" lazy-ass "^1.6.0" - listr "^0.14.3" - lodash "^4.17.19" + listr2 "^3.8.3" + lodash "^4.17.21" log-symbols "^4.0.0" - minimist "^1.2.5" - moment "^2.29.1" + minimist "^1.2.8" ospath "^1.2.2" - pretty-bytes "^5.4.1" - ramda "~0.27.1" + pretty-bytes "^5.6.0" + process "^0.11.10" + proxy-from-env "1.0.0" request-progress "^3.0.0" - supports-color "^7.2.0" + semver "^7.5.3" + supports-color "^8.1.1" tmp "~0.2.1" untildify "^4.0.0" - url "^0.11.0" yauzl "^2.10.0" cz-conventional-changelog@2.1.0: @@ -7830,6 +7958,33 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" +data-view-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" + integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" + integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" + integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + date-fns@2.10.0: version "2.10.0" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.10.0.tgz#abd10604d8bafb0bcbd2ba2e9b0563b922ae4b6b" @@ -7840,11 +7995,6 @@ date-fns@2.25.0: resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.25.0.tgz#8c5c8f1d958be3809a9a03f4b742eba894fc5680" integrity sha512-ovYRFnTrbGPD4nqaEqescPEv1mNwvt+UTqI3Ay9SzNtey9NZnYu6E2qCcBBgJ6/2VF1zGGygpyTDITqpQQ5e+w== -date-fns@^1.27.2: - version "1.30.1" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" - integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw== - date-fns@^2.30.0: version "2.30.0" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0" @@ -7857,7 +8007,7 @@ dateformat@3.0.3, dateformat@^3.0.0: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== -dayjs@^1.9.3: +dayjs@^1.10.4: version "1.11.10" resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0" integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ== @@ -7883,13 +8033,6 @@ debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, d dependencies: ms "2.1.2" -debug@4.3.2: - version "4.3.2" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" - integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== - dependencies: - ms "2.1.2" - debug@^3.1.0, debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -7922,6 +8065,13 @@ decimal.js@^10.2.1: resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== +decode-named-character-reference@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz#daabac9690874c394c81e4162a0304b35d824f0e" + integrity sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg== + dependencies: + character-entities "^2.0.0" + decode-uri-component@^0.2.0: version "0.2.2" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" @@ -8097,7 +8247,7 @@ defer-to-connect@^2.0.0: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== -define-data-property@^1.0.1, define-data-property@^1.1.2, define-data-property@^1.1.4: +define-data-property@^1.0.1, define-data-property@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== @@ -8142,7 +8292,7 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" -defu@^6.1.3: +defu@^6.1.4: version "6.1.4" resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.4.tgz#4e0c9cf9ff68fe5f3d7f2765cc1a012dfdcb0479" integrity sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg== @@ -8210,7 +8360,7 @@ deprecation@^2.0.0: resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== -dequal@^2.0.2, dequal@^2.0.3: +dequal@^2.0.0, dequal@^2.0.2, dequal@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== @@ -8233,13 +8383,6 @@ destroy@~1.0.4: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg== -detab@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/detab/-/detab-2.0.4.tgz#b927892069aff405fbb9a186fe97a44a92a94b43" - integrity sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g== - dependencies: - repeat-string "^1.5.4" - detect-file@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" @@ -8251,9 +8394,9 @@ detect-indent@^6.1.0: integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== detect-libc@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.2.tgz#8ccf2ba9315350e1241b88d0ac3b0e1fbd99605d" - integrity sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw== + version "2.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" + integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== detect-node-es@^1.1.0: version "1.1.0" @@ -8355,6 +8498,13 @@ detective-typescript@^5.8.0: node-source-walk "^4.2.0" typescript "^3.8.3" +devlop@^1.0.0, devlop@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/devlop/-/devlop-1.1.0.tgz#4db7c2ca4dc6e0e834c30be70c94bbc976dc7018" + integrity sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA== + dependencies: + dequal "^2.0.0" + diagnostics@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/diagnostics/-/diagnostics-1.1.1.tgz#cab6ac33df70c9d9a727490ae43ac995a769b22a" @@ -8663,14 +8813,14 @@ duplexify@^3.4.2, duplexify@^3.5.0, duplexify@^3.6.0: stream-shift "^1.0.0" duplexify@^4.1.1: - version "4.1.2" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-4.1.2.tgz#18b4f8d28289132fa0b9573c898d9f903f81c7b0" - integrity sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw== + version "4.1.3" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-4.1.3.tgz#a07e1c0d0a2c001158563d32592ba58bddb0236f" + integrity sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA== dependencies: end-of-stream "^1.4.1" inherits "^2.0.3" readable-stream "^3.1.1" - stream-shift "^1.0.0" + stream-shift "^1.0.2" eastasianwidth@^0.2.0: version "0.2.0" @@ -8696,9 +8846,9 @@ ejs@^2.6.1: integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA== ejs@^3.1.8: - version "3.1.9" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.9.tgz#03c9e8777fe12686a9effcef22303ca3d8eeb361" - integrity sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ== + version "3.1.10" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b" + integrity sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA== dependencies: jake "^10.8.5" @@ -8836,9 +8986,9 @@ electron-store@5.1.1: type-fest "^0.7.1" electron-to-chromium@^1.4.668: - version "1.4.690" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.690.tgz#dd5145d45c49c08a9a6f7454127e660bdf9a3fa7" - integrity sha512-+2OAGjUx68xElQhydpcbqH50hE8Vs2K6TkAeLhICYfndb67CVH0UsZaijmRUE3rHlIxU1u0jxwhgVe6fK3YANA== + version "1.4.746" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.746.tgz#787213e75f6c7bccb55dfe8b68170555c548d093" + integrity sha512-jeWaIta2rIG2FzHaYIhSuVWqC6KJYo7oSBX4Jv7g+aVujKztfvdpf+n6MGwZdC5hQXbax4nntykLH2juIQrfPg== electron-updater@4.1.2: version "4.1.2" @@ -8863,15 +9013,10 @@ electron@27.0.0: "@types/node" "^18.11.18" extract-zip "^2.0.1" -elegant-spinner@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" - integrity sha512-B+ZM+RXvRqQaAmkMlO/oSe5nMUOaUnyfGYCEHoR8wrXsZR2mA0XVibsxV1bvTwxdRWah1PkQqso2EzhILGHtEQ== - -elliptic@^6.5.3, elliptic@^6.5.4: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== +elliptic@^6.5.3, elliptic@^6.5.5: + version "6.5.5" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.5.tgz#c715e09f78b6923977610d4c2346d6ce22e6dded" + integrity sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw== dependencies: bn.js "^4.11.9" brorand "^1.1.0" @@ -8950,6 +9095,14 @@ enhanced-resolve@^4.1.0, enhanced-resolve@^4.1.1, enhanced-resolve@^4.5.0: memory-fs "^0.5.0" tapable "^1.0.0" +enquirer@^2.3.6: + version "2.4.1" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.4.1.tgz#93334b3fbd74fc7097b224ab4a8fb7e40bf4ae56" + integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== + dependencies: + ansi-colors "^4.1.1" + strip-ansi "^6.0.1" + entities@^1.1.1, entities@~1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" @@ -8971,9 +9124,9 @@ env-variable@0.0.x: integrity sha512-bHz59NlBbtS0NhftmR8+ExBEekE7br0e01jw+kk0NDro7TtZzBYZ5ScGPs3OmwnpyfHTHOtr1Y6uedCdrIldtg== envinfo@^7.7.3: - version "7.11.1" - resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.11.1.tgz#2ffef77591057081b0129a8fd8cf6118da1b94e1" - integrity sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg== + version "7.12.0" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.12.0.tgz#b56723b39c2053d67ea5714f026d05d4f5cc7acd" + integrity sha512-Iw9rQJBGpJRd3rwXm9ft/JiGoAZmLxxJZELYDQoPRZ4USVhkKtIcNBPw6U+/K2mBpaqM25JSV6Yl4Az9vO2wJg== err-code@^2.0.2: version "2.0.3" @@ -8994,17 +9147,21 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.17.2, es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.22.4: - version "1.22.5" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.5.tgz#1417df4e97cc55f09bf7e58d1e614bc61cb8df46" - integrity sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w== +es-abstract@^1.17.2, es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.1, es-abstract@^1.23.2: + version "1.23.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" + integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== dependencies: array-buffer-byte-length "^1.0.1" arraybuffer.prototype.slice "^1.0.3" available-typed-arrays "^1.0.7" call-bind "^1.0.7" + data-view-buffer "^1.0.1" + data-view-byte-length "^1.0.1" + data-view-byte-offset "^1.0.0" es-define-property "^1.0.0" es-errors "^1.3.0" + es-object-atoms "^1.0.0" es-set-tostringtag "^2.0.3" es-to-primitive "^1.2.1" function.prototype.name "^1.1.6" @@ -9015,10 +9172,11 @@ es-abstract@^1.17.2, es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.22 has-property-descriptors "^1.0.2" has-proto "^1.0.3" has-symbols "^1.0.3" - hasown "^2.0.1" + hasown "^2.0.2" internal-slot "^1.0.7" is-array-buffer "^3.0.4" is-callable "^1.2.7" + is-data-view "^1.0.1" is-negative-zero "^2.0.3" is-regex "^1.1.4" is-shared-array-buffer "^1.0.3" @@ -9029,17 +9187,17 @@ es-abstract@^1.17.2, es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.22 object-keys "^1.1.1" object.assign "^4.1.5" regexp.prototype.flags "^1.5.2" - safe-array-concat "^1.1.0" + safe-array-concat "^1.1.2" safe-regex-test "^1.0.3" - string.prototype.trim "^1.2.8" - string.prototype.trimend "^1.0.7" - string.prototype.trimstart "^1.0.7" + string.prototype.trim "^1.2.9" + string.prototype.trimend "^1.0.8" + string.prototype.trimstart "^1.0.8" typed-array-buffer "^1.0.2" typed-array-byte-length "^1.0.1" typed-array-byte-offset "^1.0.2" - typed-array-length "^1.0.5" + typed-array-length "^1.0.6" unbox-primitive "^1.0.2" - which-typed-array "^1.1.14" + which-typed-array "^1.1.15" es-array-method-boxes-properly@^1.0.0: version "1.0.0" @@ -9053,7 +9211,7 @@ es-define-property@^1.0.0: dependencies: get-intrinsic "^1.2.4" -es-errors@^1.0.0, es-errors@^1.1.0, es-errors@^1.2.1, es-errors@^1.3.0: +es-errors@^1.1.0, es-errors@^1.2.1, es-errors@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== @@ -9074,32 +9232,38 @@ es-get-iterator@^1.1.3: stop-iteration-iterator "^1.0.0" es-iterator-helpers@^1.0.17: - version "1.0.17" - resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.17.tgz#123d1315780df15b34eb181022da43e734388bb8" - integrity sha512-lh7BsUqelv4KUbR5a/ZTaGGIMLCjPGPqJ6q+Oq24YP0RdyptX1uzm4vvaqzk7Zx3bpl/76YLTTDj9L7uYQ92oQ== + version "1.0.18" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.18.tgz#4d3424f46b24df38d064af6fbbc89274e29ea69d" + integrity sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA== dependencies: - asynciterator.prototype "^1.0.0" call-bind "^1.0.7" define-properties "^1.2.1" - es-abstract "^1.22.4" + es-abstract "^1.23.0" es-errors "^1.3.0" - es-set-tostringtag "^2.0.2" + es-set-tostringtag "^2.0.3" function-bind "^1.1.2" get-intrinsic "^1.2.4" globalthis "^1.0.3" has-property-descriptors "^1.0.2" - has-proto "^1.0.1" + has-proto "^1.0.3" has-symbols "^1.0.3" internal-slot "^1.0.7" iterator.prototype "^1.1.2" - safe-array-concat "^1.1.0" + safe-array-concat "^1.1.2" es-module-lexer@^0.9.3: version "0.9.3" resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== -es-set-tostringtag@^2.0.2, es-set-tostringtag@^2.0.3: +es-object-atoms@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" + integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== @@ -9210,6 +9374,35 @@ esbuild@^0.19.3: "@esbuild/win32-ia32" "0.19.12" "@esbuild/win32-x64" "0.19.12" +esbuild@^0.20.1: + version "0.20.2" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.20.2.tgz#9d6b2386561766ee6b5a55196c6d766d28c87ea1" + integrity sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g== + optionalDependencies: + "@esbuild/aix-ppc64" "0.20.2" + "@esbuild/android-arm" "0.20.2" + "@esbuild/android-arm64" "0.20.2" + "@esbuild/android-x64" "0.20.2" + "@esbuild/darwin-arm64" "0.20.2" + "@esbuild/darwin-x64" "0.20.2" + "@esbuild/freebsd-arm64" "0.20.2" + "@esbuild/freebsd-x64" "0.20.2" + "@esbuild/linux-arm" "0.20.2" + "@esbuild/linux-arm64" "0.20.2" + "@esbuild/linux-ia32" "0.20.2" + "@esbuild/linux-loong64" "0.20.2" + "@esbuild/linux-mips64el" "0.20.2" + "@esbuild/linux-ppc64" "0.20.2" + "@esbuild/linux-riscv64" "0.20.2" + "@esbuild/linux-s390x" "0.20.2" + "@esbuild/linux-x64" "0.20.2" + "@esbuild/netbsd-x64" "0.20.2" + "@esbuild/openbsd-x64" "0.20.2" + "@esbuild/sunos-x64" "0.20.2" + "@esbuild/win32-arm64" "0.20.2" + "@esbuild/win32-ia32" "0.20.2" + "@esbuild/win32-x64" "0.20.2" + escalade@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" @@ -9246,10 +9439,12 @@ escodegen@^2.0.0, escodegen@^2.1.0: optionalDependencies: source-map "~0.6.1" -eslint-compat-utils@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/eslint-compat-utils/-/eslint-compat-utils-0.1.2.tgz#f45e3b5ced4c746c127cf724fb074cd4e730d653" - integrity sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg== +eslint-compat-utils@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/eslint-compat-utils/-/eslint-compat-utils-0.5.0.tgz#f7b2eb2befec25a370fac76934d3f9189f312a65" + integrity sha512-dc6Y8tzEcSYZMHa+CMPLi/hyo1FzNeonbhJL7Ol0ccuKQkwopJcJBA9YL/xmMTLU1eKigXo9vj9nALElWYSowg== + dependencies: + semver "^7.5.4" eslint-config-prettier@^8.1.0: version "8.10.0" @@ -9291,20 +9486,20 @@ eslint-module-utils@^2.8.0: debug "^3.2.7" eslint-plugin-cypress@^2.11.2: - version "2.15.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-2.15.1.tgz#336afa7e8e27451afaf65aa359c9509e0a4f3a7b" - integrity sha512-eLHLWP5Q+I4j2AWepYq0PgFEei9/s5LvjuSqWrxurkg1YZ8ltxdvMNmdSf0drnsNo57CTgYY/NIHHLRSWejR7w== + version "2.15.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-2.15.2.tgz#f22e12fad4c434edad7b298ef92bac8fa087ffa0" + integrity sha512-CtcFEQTDKyftpI22FVGpx8bkpKyYXBlNge6zSo0pl5/qJvBAnzaD76Vu2AsP16d6mTj478Ldn2mhgrWV+Xr0vQ== dependencies: globals "^13.20.0" eslint-plugin-es-x@^7.5.0: - version "7.5.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-es-x/-/eslint-plugin-es-x-7.5.0.tgz#d08d9cd155383e35156c48f736eb06561d07ba92" - integrity sha512-ODswlDSO0HJDzXU0XvgZ3lF3lS3XAZEossh15Q2UHjwrJggWeBoKqqEsLTZLXl+dh5eOAozG0zRcYtuE35oTuQ== + version "7.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-es-x/-/eslint-plugin-es-x-7.6.0.tgz#ccee7a4556c0f816d1ae88fd0eea21540e8ccd65" + integrity sha512-I0AmeNgevgaTR7y2lrVCJmGYF0rjoznpDvqV/kIkZSZbZ8Rw3eu4cGlvBBULScfkSOCzqKbff5LR4CNrV7mZHA== dependencies: "@eslint-community/eslint-utils" "^4.1.2" "@eslint-community/regexpp" "^4.6.0" - eslint-compat-utils "^0.1.2" + eslint-compat-utils "^0.5.0" eslint-plugin-import@^2.29.1: version "2.29.1" @@ -9365,14 +9560,14 @@ eslint-plugin-react-hooks@^4.6.0: integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== eslint-plugin-react-refresh@^0.4.4: - version "0.4.5" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.5.tgz#6b9b307bad3feba2244ef64a1a15485ac70a2d0f" - integrity sha512-D53FYKJa+fDmZMtriODxvhwrO+IOqrxoEo21gMA0sjHdU6dPVH4OhyFip9ypl8HOF5RV5KdTo+rBQLvnY2cO8w== + version "0.4.6" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.6.tgz#e8e8accab681861baed00c5c12da70267db0936f" + integrity sha512-NjGXdm7zgcKRkKMua34qVO9doI7VOxZ6ancSvBELJSSoX97jyndXcSoa8XBh69JoB31dNz3EEzlMcizZl7LaMA== eslint-plugin-react@^7.22.0: - version "7.34.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.34.0.tgz#ab71484d54fc409c37025c5eca00eb4177a5e88c" - integrity sha512-MeVXdReleBTdkz/bvcQMSnCXGi+c9kvy51IpinjnJgutl3YTHWsDdke7Z1ufZpGfDG8xduBDKyjtB9JH1eBKIQ== + version "7.34.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz#6806b70c97796f5bbfb235a5d3379ece5f4da997" + integrity sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw== dependencies: array-includes "^3.1.7" array.prototype.findlast "^1.2.4" @@ -9409,9 +9604,9 @@ eslint-plugin-storybook@^0.8.0: ts-dedent "^2.2.0" eslint-plugin-testing-library@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-testing-library/-/eslint-plugin-testing-library-6.2.0.tgz#af3340b783c881eb19ec5ac6b3a4bfe8ab4a1f74" - integrity sha512-+LCYJU81WF2yQ+Xu4A135CgK8IszcFcyMF4sWkbiu6Oj+Nel0TrkZq/HvDw0/1WuO3dhDQsZA/OpEMGd0NfcUw== + version "6.2.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-testing-library/-/eslint-plugin-testing-library-6.2.2.tgz#67e84ff891a2b3a8078ced0afa95ee6f343c00c1" + integrity sha512-1E94YOTUDnOjSLyvOwmbVDzQi/WkKm3WVrMXu6SmBr6DN95xTGZmI6HJ/eOkSXh/DlheRsxaPsJvZByDBhWLVQ== dependencies: "@typescript-eslint/utils" "^5.58.0" @@ -9531,6 +9726,11 @@ estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== +estree-util-is-identifier-name@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz#0b5ef4c4ff13508b34dcd01ecfa945f61fce5dbd" + integrity sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg== + estree-walker@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" @@ -9558,10 +9758,10 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== -eventemitter2@^6.4.2: - version "6.4.9" - resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.9.tgz#41f2750781b4230ed58827bc119d293471ecb125" - integrity sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg== +eventemitter2@6.4.7: + version "6.4.7" + resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.7.tgz#a7f6c4d7abf28a14c1ef3442f21cb306a054271d" + integrity sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg== eventemitter3@^4.0.0: version "4.0.7" @@ -9611,20 +9811,7 @@ execa@4.0.0: signal-exit "^3.0.2" strip-final-newline "^2.0.0" -execa@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -execa@^4.0.2: +execa@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== @@ -9639,6 +9826,19 @@ execa@^4.0.2: signal-exit "^3.0.2" strip-final-newline "^2.0.0" +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + execa@^5.0.0, execa@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" @@ -9683,11 +9883,6 @@ executable@^4.1.1: dependencies: pify "^2.2.0" -exit-hook@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" - integrity sha512-MsG3prOVw1WtLXAZbM3KiYtooKR1LvxHh3VHsVtIy0uiUu8usxgB/94DP2HxtD/661lLdB6yzQ09lGJSQr6nkg== - expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" @@ -9755,16 +9950,16 @@ express@4.16.4: vary "~1.1.2" express@^4.16.3, express@^4.16.4, express@^4.17.1, express@^4.17.3: - version "4.18.3" - resolved "https://registry.yarnpkg.com/express/-/express-4.18.3.tgz#6870746f3ff904dee1819b82e4b51509afffb0d4" - integrity sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw== + version "4.19.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465" + integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== dependencies: accepts "~1.3.8" array-flatten "1.1.1" body-parser "1.20.2" content-disposition "0.5.4" content-type "~1.0.4" - cookie "0.5.0" + cookie "0.6.0" cookie-signature "1.0.6" debug "2.6.9" depd "2.0.0" @@ -9840,17 +10035,7 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extract-zip@^1.6.6, extract-zip@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.7.0.tgz#556cc3ae9df7f452c493a0cfb51cc30277940927" - integrity sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA== - dependencies: - concat-stream "^1.6.2" - debug "^2.6.9" - mkdirp "^0.5.4" - yauzl "^2.10.0" - -extract-zip@^2.0.1: +extract-zip@2.0.1, extract-zip@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== @@ -9861,6 +10046,16 @@ extract-zip@^2.0.1: optionalDependencies: "@types/yauzl" "^2.9.1" +extract-zip@^1.6.6: + version "1.7.0" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.7.0.tgz#556cc3ae9df7f452c493a0cfb51cc30277940927" + integrity sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA== + dependencies: + concat-stream "^1.6.2" + debug "^2.6.9" + mkdirp "^0.5.4" + yauzl "^2.10.0" + extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" @@ -9985,18 +10180,10 @@ figgy-pudding@^3.5.1: resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw== -figures@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" - integrity sha512-UxKlfCRuCBxSXU4C6t9scbDyWZ4VlaFFdojKtzJuSkuOBQ5CNFum+zZXFwHjo+CxBC1t6zlYPgHIgFjL8ggoEQ== - dependencies: - escape-string-regexp "^1.0.5" - object-assign "^4.1.0" - -figures@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - integrity sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA== +figures@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== dependencies: escape-string-regexp "^1.0.5" @@ -10262,9 +10449,9 @@ flatten@^1.0.2: integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg== flow-parser@0.*: - version "0.229.2" - resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.229.2.tgz#b19ce67bfbfab8c91ee51dcddb9c3ab0f3bf2ab7" - integrity sha512-T72XV2Izvl7yV6dhHhLaJ630Y6vOZJl6dnOS6dN0bPW9ExuREu7xGAf3omtcxX76POTuux9TJPu9ZpS48a/rdw== + version "0.234.0" + resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.234.0.tgz#92af26f40ea7e79ca4bd66a066d6d6aa3b4223bf" + integrity sha512-J1Wn32xDF1l8FqwshoQnTwC9K3aJ83MFuXUx9AcBQr8ttbI/rkjEgAqnjxaIJuZ6RGMfccN5ZxDJSOMM64qy9Q== flush-write-stream@^1.0.0: version "1.1.1" @@ -10275,9 +10462,9 @@ flush-write-stream@^1.0.0: readable-stream "^2.3.6" follow-redirects@^1.0.0, follow-redirects@^1.14.0: - version "1.15.5" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.5.tgz#54d4d6d062c0fa7d9d17feb008461550e3ba8020" - integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw== + version "1.15.6" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" + integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== for-each@^0.3.3: version "0.3.3" @@ -10451,7 +10638,7 @@ fs-extra@^8.1.0: jsonfile "^4.0.0" universalify "^0.1.0" -fs-extra@^9.0.0, fs-extra@^9.0.1: +fs-extra@^9.0.0, fs-extra@^9.0.1, fs-extra@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== @@ -10553,7 +10740,7 @@ get-func-name@^2.0.1, get-func-name@^2.0.2: resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== -get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: +get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== @@ -10658,9 +10845,9 @@ get-symbol-description@^1.0.2: get-intrinsic "^1.2.4" get-tsconfig@^4.7.0: - version "4.7.2" - resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.2.tgz#0dcd6fb330391d46332f4c6c1bf89a6514c2ddce" - integrity sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A== + version "4.7.3" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.3.tgz#0498163d98f7b58484dd4906999c0c9d5f103f83" + integrity sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg== dependencies: resolve-pkg-maps "^1.0.0" @@ -10684,17 +10871,17 @@ getpass@^0.1.1: assert-plus "^1.0.0" giget@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/giget/-/giget-1.2.1.tgz#4f42779aae57a5f664a1c4d50401b008e9810f4c" - integrity sha512-4VG22mopWtIeHwogGSy1FViXVo0YT+m6BrqZfz0JJFwbSsePsCdOzdLIIli5BtMp7Xe8f/o2OmBpQX2NBOC24g== + version "1.2.3" + resolved "https://registry.yarnpkg.com/giget/-/giget-1.2.3.tgz#ef6845d1140e89adad595f7f3bb60aa31c672cb6" + integrity sha512-8EHPljDvs7qKykr6uw8b+lqLiUc/vUg+KVTI0uND4s63TdsZM2Xus3mflvF0DDG9SiM4RlCkFGL+7aAjRmV7KA== dependencies: - citty "^0.1.5" + citty "^0.1.6" consola "^3.2.3" - defu "^6.1.3" - node-fetch-native "^1.6.1" - nypm "^0.3.3" + defu "^6.1.4" + node-fetch-native "^1.6.3" + nypm "^0.3.8" ohash "^1.1.3" - pathe "^1.1.1" + pathe "^1.1.2" tar "^6.2.0" git-raw-commits@^2.0.8: @@ -10776,15 +10963,15 @@ glob-to-regexp@^0.4.1: integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== glob@^10.0.0, glob@^10.3.10: - version "10.3.10" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" - integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== + version "10.3.12" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.12.tgz#3a65c363c2e9998d220338e88a5f6ac97302960b" + integrity sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg== dependencies: foreground-child "^3.1.0" - jackspeak "^2.3.5" + jackspeak "^2.3.6" minimatch "^9.0.1" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - path-scurry "^1.10.1" + minipass "^7.0.4" + path-scurry "^1.10.2" glob@^7.0.0, glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.0: version "7.2.3" @@ -10821,12 +11008,12 @@ global-agent@^3.0.0: semver "^7.3.2" serialize-error "^7.0.1" -global-dirs@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.1.0.tgz#e9046a49c806ff04d6c1825e196c8f0091e8df4d" - integrity sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ== +global-dirs@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-3.0.1.tgz#0c488971f066baceda21447aecb1a8b911d22485" + integrity sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA== dependencies: - ini "1.3.7" + ini "2.0.0" global-modules@^1.0.0: version "1.0.0" @@ -11107,7 +11294,7 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.1, has-property-descriptors@^1.0.2: +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== @@ -11136,7 +11323,7 @@ has-to-string-tag-x@^1.2.0: dependencies: has-symbol-support-x "^1.4.1" -has-tostringtag@^1.0.0, has-tostringtag@^1.0.1, has-tostringtag@^1.0.2: +has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== @@ -11193,6 +11380,14 @@ hash-base@^3.0.0: readable-stream "^3.6.0" safe-buffer "^5.2.0" +hash-base@~3.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + integrity sha512-EeeoJKjTyt868liAlVmcv2ZsUfGHlE3Q+BICOXcZiwN3osr5Q/zFGYmTJpoIzuaSTAwndFy+GqhEwlU4L3j4Ow== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + hash.js@^1.0.0, hash.js@^1.0.3: version "1.1.7" resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" @@ -11201,26 +11396,13 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" -hasown@^2.0.0, hasown@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.1.tgz#26f48f039de2c0f8d3356c223fb8d50253519faa" - integrity sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA== +hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== dependencies: function-bind "^1.1.2" -hast-to-hyperscript@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/hast-to-hyperscript/-/hast-to-hyperscript-4.0.0.tgz#3eb25483ec72a8e9a71e4b1ad7eb8f7c86f755db" - integrity sha512-4kOn4ihjDJTQg7B53ZcZ6NyExtTeG3hLNZv6rSKhq4haQvD52zCllE+49iLiC1VWuc4DbHmt96FHPGlHbslZqQ== - dependencies: - comma-separated-tokens "^1.0.0" - is-nan "^1.2.1" - kebab-case "^1.0.0" - property-information "^3.0.0" - space-separated-tokens "^1.0.0" - trim "0.0.1" - unist-util-is "^2.0.0" - hast-util-from-parse5@^5.0.0: version "5.0.3" resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-5.0.3.tgz#3089dc0ee2ccf6ec8bc416919b51a54a589e097c" @@ -11247,13 +11429,6 @@ hast-util-parse-selector@^2.0.0: resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz#d57c23f4da16ae3c63b3b6ca4616683313499c3a" integrity sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ== -hast-util-sanitize@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/hast-util-sanitize/-/hast-util-sanitize-1.3.1.tgz#4e60d66336bd67e52354d581967467029a933f2e" - integrity sha512-AIeKHuHx0Wk45nSkGVa2/ujQYTksnDl8gmmKo/mwQi7ag7IBZ8cM3nJ2G86SajbjGP/HRpud6kMkPtcM2i0Tlw== - dependencies: - xtend "^4.0.1" - hast-util-to-html@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/hast-util-to-html/-/hast-util-to-html-6.1.0.tgz#86bcd19c3bd46af456984f8f34db16298c2b10b0" @@ -11270,11 +11445,39 @@ hast-util-to-html@^6.0.0: unist-util-is "^3.0.0" xtend "^4.0.1" +hast-util-to-jsx-runtime@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz#3ed27caf8dc175080117706bf7269404a0aa4f7c" + integrity sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ== + dependencies: + "@types/estree" "^1.0.0" + "@types/hast" "^3.0.0" + "@types/unist" "^3.0.0" + comma-separated-tokens "^2.0.0" + devlop "^1.0.0" + estree-util-is-identifier-name "^3.0.0" + hast-util-whitespace "^3.0.0" + mdast-util-mdx-expression "^2.0.0" + mdast-util-mdx-jsx "^3.0.0" + mdast-util-mdxjs-esm "^2.0.0" + property-information "^6.0.0" + space-separated-tokens "^2.0.0" + style-to-object "^1.0.0" + unist-util-position "^5.0.0" + vfile-message "^4.0.0" + hast-util-whitespace@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-1.0.4.tgz#e4fe77c4a9ae1cb2e6c25e02df0043d0164f6e41" integrity sha512-I5GTdSfhYfAPNztx2xJRQpG8cuDSNt599/7YUn7Gx/WxNMsG+a835k97TDkFgk123cwjfwINaZknkKkphx/f2A== +hast-util-whitespace@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz#7778ed9d3c92dd9e8c5c8f648a49c21fc51cb621" + integrity sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw== + dependencies: + "@types/hast" "^3.0.0" + hastscript@^5.0.0: version "5.1.2" resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-5.1.2.tgz#bde2c2e56d04c62dd24e8c5df288d050a355fb8a" @@ -11435,6 +11638,11 @@ html-tags@^3.0.0, html-tags@^3.1.0: resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.3.1.tgz#a04026a18c882e4bba8a01a3d39cfe465d40b5ce" integrity sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ== +html-url-attributes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/html-url-attributes/-/html-url-attributes-3.0.0.tgz#fc4abf0c3fb437e2329c678b80abb3c62cff6f08" + integrity sha512-/sXbVCWayk6GDVg3ctOX6nxaVj7So40FcFAnWlWGNAB1LpYKcV5Cd10APjPjW80O7zYW2MsjBV4zZ7IZO5fVow== + html-void-elements@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-1.0.5.tgz#ce9159494e86d95e45795b166c2021c2cfca4483" @@ -11797,22 +12005,27 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== -ini@1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" - integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ== +ini@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" + integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== ini@^1.3.2, ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: version "1.3.8" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== +inline-style-parser@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.2.3.tgz#e35c5fb45f3a83ed7849fe487336eb7efa25971c" + integrity sha512-qlD8YNDqyTKTyuITrDOffsl6Tdhv+UC4hcdAVuQsK4IMQ99nSgd1MIA/Q+jQYoh9r3hVUXhYh7urSRmXPkW04g== + interactjs@^1.10.17: - version "1.10.26" - resolved "https://registry.yarnpkg.com/interactjs/-/interactjs-1.10.26.tgz#ad009a46ee3610cb75de6aec22ea6cc0b0e277e2" - integrity sha512-5gNTNDTfEHp2EifqtWGi5VkD3CMZVJSTGmtK/IsVRd+rkOk3E63iVs5Z+IeD5K1Lr0qZpU2754VHAwf5i+Z9xg== + version "1.10.27" + resolved "https://registry.yarnpkg.com/interactjs/-/interactjs-1.10.27.tgz#16499aba4987a5ccfdaddca7d1ba7bb1118e14d0" + integrity sha512-y/8RcCftGAF24gSp76X2JS3XpHiUvDQyhF8i7ujemBz77hwiHDuJzftHx7thY8cxGogwGiPJ+o97kWB6eAXnsA== dependencies: - "@interactjs/types" "1.10.26" + "@interactjs/types" "1.10.27" internal-ip@^4.3.0: version "4.3.0" @@ -11822,7 +12035,7 @@ internal-ip@^4.3.0: default-gateway "^4.2.0" ipaddr.js "^1.9.0" -internal-slot@^1.0.4, internal-slot@^1.0.5, internal-slot@^1.0.7: +internal-slot@^1.0.4, internal-slot@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== @@ -11906,6 +12119,11 @@ is-alphabetical@^1.0.0: resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== +is-alphabetical@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-2.0.1.tgz#01072053ea7c1036df3c7d19a6daaec7f19e789b" + integrity sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ== + is-alphanumeric@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz#4a9cef71daf4c001c1d81d63d140cf53fd6889f4" @@ -11919,6 +12137,14 @@ is-alphanumerical@^1.0.0: is-alphabetical "^1.0.0" is-decimal "^1.0.0" +is-alphanumerical@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz#7c03fbe96e3e931113e57f964b0a368cc2dfd875" + integrity sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw== + dependencies: + is-alphabetical "^2.0.0" + is-decimal "^2.0.0" + is-arguments@^1.0.4, is-arguments@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" @@ -11981,7 +12207,7 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-buffer@^1.1.4, is-buffer@^1.1.5: +is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== @@ -12010,14 +12236,7 @@ is-ci@^1.1.0: dependencies: ci-info "^1.5.0" -is-ci@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" - integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== - dependencies: - ci-info "^2.0.0" - -is-ci@^3.0.0: +is-ci@^3.0.0, is-ci@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-3.0.1.tgz#db6ecbed1bd659c43dac0f45661e7674103d1867" integrity sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ== @@ -12050,6 +12269,13 @@ is-data-descriptor@^1.0.1: dependencies: hasown "^2.0.0" +is-data-view@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" + integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== + dependencies: + is-typed-array "^1.1.13" + is-date-object@^1.0.1, is-date-object@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" @@ -12062,6 +12288,11 @@ is-decimal@^1.0.0, is-decimal@^1.0.2: resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== +is-decimal@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-2.0.1.tgz#9469d2dc190d0214fd87d78b78caecc0cc14eef7" + integrity sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A== + is-deflate@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-deflate/-/is-deflate-1.0.0.tgz#c862901c3c161fb09dac7cdc7e784f80e98f2f14" @@ -12117,13 +12348,6 @@ is-finalizationregistry@^1.0.2: dependencies: call-bind "^1.0.2" -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw== - dependencies: - number-is-nan "^1.0.0" - is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" @@ -12165,13 +12389,18 @@ is-hexadecimal@^1.0.0: resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== -is-installed-globally@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141" - integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g== +is-hexadecimal@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz#86b5bf668fca307498d319dfc03289d781a90027" + integrity sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg== + +is-installed-globally@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" + integrity sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ== dependencies: - global-dirs "^2.0.1" - is-path-inside "^3.0.1" + global-dirs "^3.0.0" + is-path-inside "^3.0.2" is-interactive@^1.0.0: version "1.0.0" @@ -12190,17 +12419,17 @@ is-lambda@^1.0.1: resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== -is-map@^2.0.1, is-map@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" - integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== +is-map@^2.0.2, is-map@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" + integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== is-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g== -is-nan@^1.2.1, is-nan@^1.3.2: +is-nan@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== @@ -12252,13 +12481,6 @@ is-object@^1.0.1: resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf" integrity sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA== -is-observable@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-observable/-/is-observable-1.1.0.tgz#b3e986c8f44de950867cab5403f5a3465005975e" - integrity sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA== - dependencies: - symbol-observable "^1.1.0" - is-path-cwd@^2.0.0, is-path-cwd@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" @@ -12278,7 +12500,7 @@ is-path-inside@^2.1.0: dependencies: path-is-inside "^1.0.2" -is-path-inside@^3.0.1, is-path-inside@^3.0.2, is-path-inside@^3.0.3: +is-path-inside@^3.0.2, is-path-inside@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== @@ -12293,6 +12515,11 @@ is-plain-obj@^2.0.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== +is-plain-obj@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0" + integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg== + is-plain-object@5.0.0, is-plain-object@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" @@ -12310,11 +12537,6 @@ is-potential-custom-element-name@^1.0.1: resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== -is-promise@^2.1.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" - integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== - is-reference@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7" @@ -12355,10 +12577,10 @@ is-retry-allowed@^1.1.0: resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== -is-set@^2.0.1, is-set@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" - integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== +is-set@^2.0.2, is-set@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" + integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: version "1.0.3" @@ -12425,10 +12647,10 @@ is-url@^1.2.4: resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww== -is-weakmap@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" - integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== +is-weakmap@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" + integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== is-weakref@^1.0.2: version "1.0.2" @@ -12437,13 +12659,13 @@ is-weakref@^1.0.2: dependencies: call-bind "^1.0.2" -is-weakset@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d" - integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg== +is-weakset@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.3.tgz#e801519df8c0c43e12ff2834eead84ec9e624007" + integrity sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" + call-bind "^1.0.7" + get-intrinsic "^1.2.4" is-whitespace-character@^1.0.0: version "1.0.4" @@ -12588,7 +12810,7 @@ iterator.prototype@^1.1.2: reflect.getprototypeof "^1.0.4" set-function-name "^2.0.1" -jackspeak@^2.3.5: +jackspeak@^2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== @@ -12675,6 +12897,11 @@ jmespath@0.16.0: resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.16.0.tgz#b15b0a85dfd4d930d43e69ed605943c802785076" integrity sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw== +jotai@2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/jotai/-/jotai-2.8.0.tgz#5a6585cd5576c400c2c5f8e157b83ad2ba70b2ab" + integrity sha512-yZNMC36FdLOksOr8qga0yLf14miCJlEThlp5DeFJNnqzm2+ZG7wLcJzoOyij5K6U6Xlc5ljQqPDlJRgqW0Y18g== + js-sdsl@4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.3.0.tgz#aeefe32a451f7af88425b11fdb5f58c90ae1d711" @@ -12846,7 +13073,7 @@ json5@^2.1.2, json5@^2.2.0, json5@^2.2.3: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== -jsonc-parser@^3.0.0, jsonc-parser@^3.2.0: +jsonc-parser@^3.0.0: version "3.2.1" resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.1.tgz#031904571ccf929d7670ee8c547545081cb37f1a" integrity sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA== @@ -12922,11 +13149,6 @@ jszip@^3.1.0: readable-stream "~2.3.6" setimmediate "^1.0.5" -kebab-case@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/kebab-case/-/kebab-case-1.0.2.tgz#5eac97d5d220acf606d40e3c0ecfea21f1f9e1eb" - integrity sha512-7n6wXq4gNgBELfDCpzKc+mRrZFs7D+wgfF5WRFLNAr4DA/qtr9Js8uOAVAfHhuLMfAcQ0pRKqbpjx+TcJVdE1Q== - keyboardevent-from-electron-accelerator@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/keyboardevent-from-electron-accelerator/-/keyboardevent-from-electron-accelerator-2.0.0.tgz#ace21b1aa4e47148815d160057f9edb66567c50c" @@ -13054,49 +13276,19 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -listr-silent-renderer@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz#924b5a3757153770bf1a8e3fbf74b8bbf3f9242e" - integrity sha512-L26cIFm7/oZeSNVhWB6faeorXhMg4HNlb/dS/7jHhr708jxlXrtrBWo4YUxZQkc6dGoxEAe6J/D3juTRBUzjtA== - -listr-update-renderer@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz#4ea8368548a7b8aecb7e06d8c95cb45ae2ede6a2" - integrity sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA== - dependencies: - chalk "^1.1.3" - cli-truncate "^0.2.1" - elegant-spinner "^1.0.1" - figures "^1.7.0" - indent-string "^3.0.0" - log-symbols "^1.0.2" - log-update "^2.3.0" - strip-ansi "^3.0.1" - -listr-verbose-renderer@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz#f1132167535ea4c1261102b9f28dac7cba1e03db" - integrity sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw== +listr2@^3.8.3: + version "3.14.0" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-3.14.0.tgz#23101cc62e1375fd5836b248276d1d2b51fdbe9e" + integrity sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g== dependencies: - chalk "^2.4.1" - cli-cursor "^2.1.0" - date-fns "^1.27.2" - figures "^2.0.0" - -listr@^0.14.3: - version "0.14.3" - resolved "https://registry.yarnpkg.com/listr/-/listr-0.14.3.tgz#2fea909604e434be464c50bddba0d496928fa586" - integrity sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA== - dependencies: - "@samverschueren/stream-to-observable" "^0.3.0" - is-observable "^1.1.0" - is-promise "^2.1.0" - is-stream "^1.1.0" - listr-silent-renderer "^1.1.1" - listr-update-renderer "^0.5.0" - listr-verbose-renderer "^0.5.0" - p-map "^2.0.0" - rxjs "^6.3.3" + 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.1" + through "^2.3.8" + wrap-ansi "^7.0.0" load-json-file@^4.0.0: version "4.0.0" @@ -13239,13 +13431,6 @@ lodash@4.17.21, lodash@^4.0.1, lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17, lod resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -log-symbols@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18" - integrity sha512-mmPrW0Fh2fxOzdBbFv4g1m6pR72haFLPJ2G5SJEELf1y+iaQrDG6cWCPjy54RHYbZAt7X+ls690Kw62AdWXBzQ== - dependencies: - chalk "^1.0.0" - log-symbols@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" @@ -13268,14 +13453,15 @@ log-symbols@^4.0.0, log-symbols@^4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" -log-update@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/log-update/-/log-update-2.3.0.tgz#88328fd7d1ce7938b29283746f0b1bc126b24708" - integrity sha512-vlP11XfFGyeNQlmEn9tJ66rEW1coA/79m5z6BCkudjbAGE83uhAcGYrBFwfs3AdLiLzGRusRPAbSPK9xZteCmg== +log-update@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" + integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== dependencies: - ansi-escapes "^3.0.0" - cli-cursor "^2.0.0" - wrap-ansi "^3.0.1" + ansi-escapes "^4.3.0" + cli-cursor "^3.1.0" + slice-ansi "^4.0.0" + wrap-ansi "^6.2.0" logform@^1.9.1: version "1.10.0" @@ -13310,6 +13496,11 @@ longest-streak@^2.0.1: resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.4.tgz#b8599957da5b5dab64dee3fe316fa774597d90e4" integrity sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg== +longest-streak@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4" + integrity sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g== + longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" @@ -13365,6 +13556,11 @@ lowercase-keys@^2.0.0: resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== +lru-cache@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3" + integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -13384,11 +13580,6 @@ lru-cache@^7.7.1: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== -"lru-cache@^9.1.1 || ^10.0.0": - version "10.2.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3" - integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== - lz-string@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941" @@ -13446,20 +13637,20 @@ magic-string@^0.27.0: "@jridgewell/sourcemap-codec" "^1.4.13" magic-string@^0.30.0, magic-string@^0.30.5: - version "0.30.8" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.8.tgz#14e8624246d2bedba70d5462aa99ac9681844613" - integrity sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ== + version "0.30.10" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.10.tgz#123d9c41a0cb5640c892b041d4cfb3bd0aa4b39e" + integrity sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ== dependencies: "@jridgewell/sourcemap-codec" "^1.4.15" magicast@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.3.3.tgz#a15760f982deec9dabc5f314e318d7c6bddcb27b" - integrity sha512-ZbrP1Qxnpoes8sz47AM0z08U+jW6TyRgZzcWy3Ma3vDhJttwMwAFDMMQFobwdBxByBD46JYmxRzeF7w2+wJEuw== + version "0.3.4" + resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.3.4.tgz#bbda1791d03190a24b00ff3dd18151e7fd381d19" + integrity sha512-TyDF/Pn36bBji9rWKHlZe+PZb6Mx5V8IHCSxk7X4aljM4e/vyDvZZYwHewdVaqiA0nb3ghfHU/6AUpDxWoER2Q== dependencies: - "@babel/parser" "^7.23.6" - "@babel/types" "^7.23.6" - source-map-js "^1.0.2" + "@babel/parser" "^7.24.4" + "@babel/types" "^7.24.0" + source-map-js "^1.2.0" make-dir@^1.0.0: version "1.3.0" @@ -13562,9 +13753,9 @@ markdown-table@^1.1.0: integrity sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q== markdown-to-jsx@^7.1.8: - version "7.4.1" - resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-7.4.1.tgz#1ed6a60f8f9cd944bec39d9923fbbc8d3d60dcb9" - integrity sha512-GbrbkTnHp9u6+HqbPRFJbObi369AgJNXi/sGqq5HRsoZW063xR1XDCaConqq+whfEIAlzB1YPnOgsPc7B7bc/A== + version "7.4.7" + resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-7.4.7.tgz#740ee7ec933865ef5cc683a0992797685a75e2ee" + integrity sha512-0+ls1IQZdU6cwM1yu0ZjjiVWYtkbExSyUIFU2ZeDIFuZM1W42Mh4OlJ4nb4apX4H8smxDHRdFaoIVJGwfv5hkg== match-sorter@^6.0.2: version "6.3.4" @@ -13607,13 +13798,6 @@ mdast-util-compact@^1.0.0: dependencies: unist-util-visit "^1.1.0" -mdast-util-definitions@^1.2.0: - version "1.2.5" - resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-1.2.5.tgz#3fe622a4171c774ebd06f11e9f8af7ec53ea5c74" - integrity sha512-CJXEdoLfiISCDc2JB6QLb79pYfI6+GcIH+W2ox9nMc7od0Pz+bovcHsiq29xAQY6ayqe/9CsK2VzkSJdg1pFYA== - dependencies: - unist-util-visit "^1.0.0" - mdast-util-definitions@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz#c5c1a84db799173b4dcf7643cda999e440c24db2" @@ -13621,28 +13805,116 @@ mdast-util-definitions@^4.0.0: dependencies: unist-util-visit "^2.0.0" -mdast-util-to-hast@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-3.0.4.tgz#132001b266031192348d3366a6b011f28e54dc40" - integrity sha512-/eIbly2YmyVgpJNo+bFLLMCI1XgolO/Ffowhf+pHDq3X4/V6FntC9sGQCDLM147eTS+uSXv5dRzJyFn+o0tazA== +mdast-util-from-markdown@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.0.tgz#52f14815ec291ed061f2922fd14d6689c810cb88" + integrity sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA== dependencies: - collapse-white-space "^1.0.0" - detab "^2.0.0" - mdast-util-definitions "^1.2.0" - mdurl "^1.0.1" - trim "0.0.1" - trim-lines "^1.0.0" - unist-builder "^1.0.1" - unist-util-generated "^1.1.0" - unist-util-position "^3.0.0" - unist-util-visit "^1.1.0" - xtend "^4.0.1" + "@types/mdast" "^4.0.0" + "@types/unist" "^3.0.0" + decode-named-character-reference "^1.0.0" + devlop "^1.0.0" + mdast-util-to-string "^4.0.0" + micromark "^4.0.0" + micromark-util-decode-numeric-character-reference "^2.0.0" + micromark-util-decode-string "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + unist-util-stringify-position "^4.0.0" + +mdast-util-mdx-expression@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz#4968b73724d320a379110d853e943a501bfd9d87" + integrity sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw== + dependencies: + "@types/estree-jsx" "^1.0.0" + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + +mdast-util-mdx-jsx@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.1.2.tgz#daae777c72f9c4a106592e3025aa50fb26068e1b" + integrity sha512-eKMQDeywY2wlHc97k5eD8VC+9ASMjN8ItEZQNGwJ6E0XWKiW/Z0V5/H8pvoXUf+y+Mj0VIgeRRbujBmFn4FTyA== + dependencies: + "@types/estree-jsx" "^1.0.0" + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + "@types/unist" "^3.0.0" + ccount "^2.0.0" + devlop "^1.1.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + parse-entities "^4.0.0" + stringify-entities "^4.0.0" + unist-util-remove-position "^5.0.0" + unist-util-stringify-position "^4.0.0" + vfile-message "^4.0.0" + +mdast-util-mdxjs-esm@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz#019cfbe757ad62dd557db35a695e7314bcc9fa97" + integrity sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg== + dependencies: + "@types/estree-jsx" "^1.0.0" + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + +mdast-util-phrasing@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz#7cc0a8dec30eaf04b7b1a9661a92adb3382aa6e3" + integrity sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w== + dependencies: + "@types/mdast" "^4.0.0" + unist-util-is "^6.0.0" + +mdast-util-to-hast@^13.0.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-13.1.0.tgz#1ae54d903150a10fe04d59f03b2b95fd210b2124" + integrity sha512-/e2l/6+OdGp/FB+ctrJ9Avz71AN/GRH3oi/3KAx/kMnoUsD6q0woXlDT8lLEeViVKE7oZxE7RXzvO3T8kF2/sA== + dependencies: + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + "@ungap/structured-clone" "^1.0.0" + devlop "^1.0.0" + micromark-util-sanitize-uri "^2.0.0" + trim-lines "^3.0.0" + unist-util-position "^5.0.0" + unist-util-visit "^5.0.0" + vfile "^6.0.0" + +mdast-util-to-markdown@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz#9813f1d6e0cdaac7c244ec8c6dabfdb2102ea2b4" + integrity sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ== + dependencies: + "@types/mdast" "^4.0.0" + "@types/unist" "^3.0.0" + longest-streak "^3.0.0" + mdast-util-phrasing "^4.0.0" + mdast-util-to-string "^4.0.0" + micromark-util-decode-string "^2.0.0" + unist-util-visit "^5.0.0" + zwitch "^2.0.0" mdast-util-to-string@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz#27055500103f51637bd07d01da01eb1967a43527" integrity sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A== +mdast-util-to-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz#7a5121475556a04e7eddeb67b264aae79d312814" + integrity sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg== + dependencies: + "@types/mdast" "^4.0.0" + mdn-data@2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" @@ -13667,11 +13939,6 @@ mdns-js@1.0.1: dns-js "~0.2.1" semver "^5.4.1" -mdurl@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" - integrity sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g== - media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -13764,6 +14031,200 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== +micromark-core-commonmark@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-2.0.0.tgz#50740201f0ee78c12a675bf3e68ffebc0bf931a3" + integrity sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA== + dependencies: + decode-named-character-reference "^1.0.0" + devlop "^1.0.0" + micromark-factory-destination "^2.0.0" + micromark-factory-label "^2.0.0" + micromark-factory-space "^2.0.0" + micromark-factory-title "^2.0.0" + micromark-factory-whitespace "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-chunked "^2.0.0" + micromark-util-classify-character "^2.0.0" + micromark-util-html-tag-name "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" + micromark-util-resolve-all "^2.0.0" + micromark-util-subtokenize "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-factory-destination@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz#857c94debd2c873cba34e0445ab26b74f6a6ec07" + integrity sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA== + dependencies: + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-factory-label@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz#17c5c2e66ce39ad6f4fc4cbf40d972f9096f726a" + integrity sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw== + dependencies: + devlop "^1.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-factory-space@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz#5e7afd5929c23b96566d0e1ae018ae4fcf81d030" + integrity sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg== + dependencies: + micromark-util-character "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-factory-title@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz#726140fc77892af524705d689e1cf06c8a83ea95" + integrity sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A== + dependencies: + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-factory-whitespace@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz#9e92eb0f5468083381f923d9653632b3cfb5f763" + integrity sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA== + dependencies: + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-util-character@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-2.1.0.tgz#31320ace16b4644316f6bf057531689c71e2aee1" + integrity sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ== + dependencies: + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-util-chunked@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz#e51f4db85fb203a79dbfef23fd41b2f03dc2ef89" + integrity sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg== + dependencies: + micromark-util-symbol "^2.0.0" + +micromark-util-classify-character@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz#8c7537c20d0750b12df31f86e976d1d951165f34" + integrity sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw== + dependencies: + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-util-combine-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz#75d6ab65c58b7403616db8d6b31315013bfb7ee5" + integrity sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ== + dependencies: + micromark-util-chunked "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-util-decode-numeric-character-reference@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz#2698bbb38f2a9ba6310e359f99fcb2b35a0d2bd5" + integrity sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ== + dependencies: + micromark-util-symbol "^2.0.0" + +micromark-util-decode-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz#7dfa3a63c45aecaa17824e656bcdb01f9737154a" + integrity sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA== + dependencies: + decode-named-character-reference "^1.0.0" + micromark-util-character "^2.0.0" + micromark-util-decode-numeric-character-reference "^2.0.0" + micromark-util-symbol "^2.0.0" + +micromark-util-encode@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz#0921ac7953dc3f1fd281e3d1932decfdb9382ab1" + integrity sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA== + +micromark-util-html-tag-name@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz#ae34b01cbe063363847670284c6255bb12138ec4" + integrity sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw== + +micromark-util-normalize-identifier@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz#91f9a4e65fe66cc80c53b35b0254ad67aa431d8b" + integrity sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w== + dependencies: + micromark-util-symbol "^2.0.0" + +micromark-util-resolve-all@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz#189656e7e1a53d0c86a38a652b284a252389f364" + integrity sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA== + dependencies: + micromark-util-types "^2.0.0" + +micromark-util-sanitize-uri@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz#ec8fbf0258e9e6d8f13d9e4770f9be64342673de" + integrity sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw== + dependencies: + micromark-util-character "^2.0.0" + micromark-util-encode "^2.0.0" + micromark-util-symbol "^2.0.0" + +micromark-util-subtokenize@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz#76129c49ac65da6e479c09d0ec4b5f29ec6eace5" + integrity sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q== + dependencies: + devlop "^1.0.0" + micromark-util-chunked "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-util-symbol@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz#12225c8f95edf8b17254e47080ce0862d5db8044" + integrity sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw== + +micromark-util-types@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-2.0.0.tgz#63b4b7ffeb35d3ecf50d1ca20e68fc7caa36d95e" + integrity sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w== + +micromark@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/micromark/-/micromark-4.0.0.tgz#84746a249ebd904d9658cfabc1e8e5f32cbc6249" + integrity sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ== + dependencies: + "@types/debug" "^4.0.0" + debug "^4.0.0" + decode-named-character-reference "^1.0.0" + devlop "^1.0.0" + micromark-core-commonmark "^2.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-chunked "^2.0.0" + micromark-util-combine-extensions "^2.0.0" + micromark-util-decode-numeric-character-reference "^2.0.0" + micromark-util-encode "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" + micromark-util-resolve-all "^2.0.0" + micromark-util-sanitize-uri "^2.0.0" + micromark-util-subtokenize "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" @@ -13831,11 +14292,6 @@ mime@^2.0.3, mime@^2.3.1, mime@^2.4.4, mime@^2.5.2: resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -13893,7 +14349,7 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== -minimatch@9.0.3, minimatch@^9.0, minimatch@^9.0.1: +minimatch@9.0.3: version "9.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== @@ -13914,6 +14370,13 @@ minimatch@^5.0.1, minimatch@^5.1.1: dependencies: brace-expansion "^2.0.1" +minimatch@^9.0, minimatch@^9.0.1: + version "9.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" + integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== + dependencies: + brace-expansion "^2.0.1" + minimist-options@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" @@ -13936,7 +14399,7 @@ minimist@0.0.8: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q== -minimist@^1.1.0, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6: +minimist@^1.1.0, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -13992,7 +14455,7 @@ minipass@^5.0.0: resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0": +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.4: version "7.0.4" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== @@ -14063,7 +14526,7 @@ mkdirp@^1.0.3, mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mlly@^1.2.0, mlly@^1.4.2: +mlly@^1.4.2, mlly@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.6.1.tgz#0983067dc3366d6314fc5e12712884e6978d028f" integrity sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA== @@ -14103,11 +14566,6 @@ module-lookup-amd@^6.1.0: requirejs "^2.3.5" requirejs-config-file "^3.1.1" -moment@^2.29.1: - version "2.30.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" - integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how== - move-concurrently@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" @@ -14202,9 +14660,9 @@ mutexify@^1.1.0: queue-tick "^1.0.0" nan@^2.12.1: - version "2.18.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.18.0.tgz#26a6faae7ffbeb293a39660e88a76b82e30b7554" - integrity sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w== + version "2.19.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.19.0.tgz#bb58122ad55a6c5bc973303908d5b16cfdd5a8c0" + integrity sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw== nano-time@1.0.0: version "1.0.0" @@ -14283,9 +14741,9 @@ no-case@^2.2.0: lower-case "^1.1.1" node-abi@^3.0.0, node-abi@^3.45.0: - version "3.56.0" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.56.0.tgz#ca807d5ff735ac6bbbd684ae3ff2debc1c2a40a7" - integrity sha512-fZjdhDOeRcaS+rcpve7XuwHBmktS1nS1gzgghwKUQQ8nTy2FdSDr6ZT8k6YhvlJeHmmQMYiT/IH9hfco5zeW2Q== + version "3.60.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.60.0.tgz#a325b13b3c401c2230202897559fbf0b5f9a90ac" + integrity sha512-zcGgwoXbzw9NczqbGzAWL/ToDYAxv1V8gL1D67ClbdkIfeeDBbY0GelZtC25ayLvVjr2q2cloHeQV1R0QAWqRQ== dependencies: semver "^7.3.5" @@ -14330,10 +14788,10 @@ node-dir@^0.1.17: dependencies: minimatch "^3.0.2" -node-fetch-native@^1.6.1: - version "1.6.2" - resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.2.tgz#f439000d972eb0c8a741b65dcda412322955e1c6" - integrity sha512-69mtXOFZ6hSkYiXAVB5SqaRvrbITC/NPyqv7yuu/qw0nmgPyYbIMYYNIDhNtwPrzk0ptrimrLz/hhjvm4w5Z+w== +node-fetch-native@^1.6.3: + version "1.6.4" + resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.4.tgz#679fc8fd8111266d47d7e72c379f1bed9acff06e" + integrity sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ== node-fetch@2.6.7: version "2.6.7" @@ -14576,17 +15034,12 @@ number-allocator@^1.0.9: debug "^4.3.1" js-sdsl "4.3.0" -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== - nwsapi@^2.2.0: - version "2.2.7" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30" - integrity sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ== + version "2.2.9" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.9.tgz#7f3303218372db2e9f27c27766bcfc59ae7e61c6" + integrity sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg== -nypm@^0.3.3: +nypm@^0.3.8: version "0.3.8" resolved "https://registry.yarnpkg.com/nypm/-/nypm-0.3.8.tgz#a16b078b161be5885351e72cf0b97326973722bf" integrity sha512-IGWlC6So2xv6V4cIDmoV0SwwWx7zLG086gyqkyumteH2fIgCAM4nDVFB2iDRszDvmdSVW9xb1N+2KjQ6C7d4og== @@ -14652,52 +15105,54 @@ object.assign@^4.1.4, object.assign@^4.1.5: object-keys "^1.1.1" object.entries@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.7.tgz#2b47760e2a2e3a752f39dd874655c61a7f03c131" - integrity sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA== + version "1.1.8" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.8.tgz#bffe6f282e01f4d17807204a24f8edd823599c41" + integrity sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" object.fromentries@^2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.7.tgz#71e95f441e9a0ea6baf682ecaaf37fa2a8d7e616" - integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== + version "2.0.8" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.0: - version "2.1.7" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.7.tgz#7a466a356cd7da4ba8b9e94ff6d35c3eeab5d56a" - integrity sha512-PrJz0C2xJ58FNn11XV2lr4Jt5Gzl94qpy9Lu0JlfEj14z88sqbSBJCBEzdlNUCzY2gburhbrwOZ5BHCmuNUy0g== + version "2.1.8" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.8.tgz#2f1fe0606ec1a7658154ccd4f728504f69667923" + integrity sha512-qkHIGe4q0lSYMv0XI4SsBTJz3WaURhLvd0lKSgtVuOsJ2krg4SgMw3PIRQFMp07yi++UR3se2mkcLqsBNpBb/A== dependencies: array.prototype.reduce "^1.0.6" - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - safe-array-concat "^1.0.0" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + gopd "^1.0.1" + safe-array-concat "^1.1.2" object.groupby@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.2.tgz#494800ff5bab78fd0eff2835ec859066e00192ec" - integrity sha512-bzBq58S+x+uo0VjurFT0UktpKHOZmv4/xePiOA1nbB9pMqpGK7rUPNgf+1YC+7mE+0HzhTMqNUuCqvKhj6FnBw== + version "1.0.3" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" + integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== dependencies: - array.prototype.filter "^1.0.3" - call-bind "^1.0.5" + call-bind "^1.0.7" define-properties "^1.2.1" - es-abstract "^1.22.3" - es-errors "^1.0.0" + es-abstract "^1.23.2" object.hasown@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.3.tgz#6a5f2897bb4d3668b8e79364f98ccf971bda55ae" - integrity sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA== + version "1.1.4" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.4.tgz#e270ae377e4c120cdcb7656ce66884a6218283dc" + integrity sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg== dependencies: - define-properties "^1.2.0" - es-abstract "^1.22.1" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" object.pick@^1.3.0: version "1.3.0" @@ -14707,13 +15162,13 @@ object.pick@^1.3.0: isobject "^3.0.1" object.values@^1.1.0, object.values@^1.1.6, object.values@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.7.tgz#617ed13272e7e1071b43973aa1655d9291b8442a" - integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== + version "1.2.0" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" + integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" objectorarray@^1.0.5: version "1.0.5" @@ -14766,18 +15221,6 @@ one-time@0.0.4: resolved "https://registry.yarnpkg.com/one-time/-/one-time-0.0.4.tgz#f8cdf77884826fe4dff93e3a9cc37b1e4480742e" integrity sha512-qAMrwuk2xLEutlASoiPiAMW3EN3K96Ka/ilSXYr6qR1zSVXw2j7+yDSqGTC4T9apfLYxM3tLLjKvgPdAUK7kYQ== -onetime@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" - integrity sha512-GZ+g4jayMqzCRMgB2sol7GiCLjKfS1PINkjmx8spcKce1LiVqcbQreXwqs2YAFXC6R03VIG28ZS31t8M866v6A== - -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ== - dependencies: - mimic-fn "^1.0.0" - onetime@^5.1.0, onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" @@ -15017,16 +15460,17 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-asn1@^5.0.0, parse-asn1@^5.1.6: - version "5.1.6" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" - integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== +parse-asn1@^5.0.0, parse-asn1@^5.1.7: + version "5.1.7" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.7.tgz#73cdaaa822125f9647165625eb45f8a051d2df06" + integrity sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg== dependencies: - asn1.js "^5.2.0" - browserify-aes "^1.0.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - safe-buffer "^5.1.1" + asn1.js "^4.10.1" + browserify-aes "^1.2.0" + evp_bytestokey "^1.0.3" + hash-base "~3.0" + pbkdf2 "^3.1.2" + safe-buffer "^5.2.1" parse-entities@^1.0.2, parse-entities@^1.1.0: version "1.2.2" @@ -15040,6 +15484,20 @@ parse-entities@^1.0.2, parse-entities@^1.1.0: is-decimal "^1.0.0" is-hexadecimal "^1.0.0" +parse-entities@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-4.0.1.tgz#4e2a01111fb1c986549b944af39eeda258fc9e4e" + integrity sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w== + dependencies: + "@types/unist" "^2.0.0" + character-entities "^2.0.0" + character-entities-legacy "^3.0.0" + character-reference-invalid "^2.0.0" + decode-named-character-reference "^1.0.0" + is-alphanumerical "^2.0.0" + is-decimal "^2.0.0" + is-hexadecimal "^2.0.0" + parse-json@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" @@ -15145,12 +15603,12 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.10.1: - version "1.10.1" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" - integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== +path-scurry@^1.10.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.2.tgz#8f6357eb1239d5fa1da8b9f70e9c080675458ba7" + integrity sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA== dependencies: - lru-cache "^9.1.1 || ^10.0.0" + lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" path-to-regexp@0.1.7: @@ -15182,7 +15640,7 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -pathe@^1.1.0, pathe@^1.1.1, pathe@^1.1.2: +pathe@^1.1.1, pathe@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ== @@ -15192,7 +15650,7 @@ pathval@^1.1.1: resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== -pbkdf2@^3.0.3: +pbkdf2@^3.0.3, pbkdf2@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== @@ -15291,13 +15749,13 @@ pkg-dir@^5.0.0: find-up "^5.0.0" pkg-types@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.0.3.tgz#988b42ab19254c01614d13f4f65a2cfc7880f868" - integrity sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A== + version "1.1.0" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.1.0.tgz#3ec1bf33379030fd0a34c227b6c650e8ea7ca271" + integrity sha512-/RpmvKdxKf8uILTtoOhAgf30wYbP2Qw+L9p3Rvshx1JZVX+XQNZQFjlbmGHEGIm4CkVPlSn+NXmIM8+9oWQaSA== dependencies: - jsonc-parser "^3.2.0" - mlly "^1.2.0" - pathe "^1.1.0" + confbox "^0.1.7" + mlly "^1.6.1" + pathe "^1.1.2" pkg-up@^3.0.1: version "3.1.0" @@ -15383,14 +15841,14 @@ postcss-clamp@^4.1.0: postcss-value-parser "^4.2.0" postcss-color-functional-notation@^6.0.2: - version "6.0.5" - resolved "https://registry.yarnpkg.com/postcss-color-functional-notation/-/postcss-color-functional-notation-6.0.5.tgz#eca158e833b5655c5715c998e92aab9481124c18" - integrity sha512-aTFsIy89ftjyclwUHRwvz1IxucLzVrzmmcXmtbPWT9GdyYeaJEKeAwbaZzOZn7AQlXg4xfwgkYhKsofC4aLIwg== - dependencies: - "@csstools/css-color-parser" "^1.5.2" - "@csstools/css-parser-algorithms" "^2.6.0" - "@csstools/css-tokenizer" "^2.2.3" - "@csstools/postcss-progressive-custom-properties" "^3.1.0" + version "6.0.9" + resolved "https://registry.yarnpkg.com/postcss-color-functional-notation/-/postcss-color-functional-notation-6.0.9.tgz#30b7a2f4f4fc0f7ccdcb720ea8d311eebb4a260b" + integrity sha512-8i/ofOArZ4fljp+3g+HI6Pok01Kb8YaSqInrJt2vMimEKrI0ZDNRLpH+wLhXBNu/Bi8zeWDvxhvCqsGSpu8E6Q== + dependencies: + "@csstools/css-color-parser" "^2.0.0" + "@csstools/css-parser-algorithms" "^2.6.1" + "@csstools/css-tokenizer" "^2.2.4" + "@csstools/postcss-progressive-custom-properties" "^3.2.0" "@csstools/utilities" "^1.0.0" postcss-color-hex-alpha@^9.0.2: @@ -15438,34 +15896,34 @@ postcss-convert-values@^4.0.1: postcss-value-parser "^3.0.0" postcss-custom-media@^10.0, postcss-custom-media@^10.0.2: - version "10.0.3" - resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-10.0.3.tgz#7131ee7f6e55cbb0423dcfca37c8946539f1b214" - integrity sha512-wfJ9nKpLn/Qy7LASKu0Rj9Iq2uMzlRt27P4FAE1889IKRMdYUgy8SqvdXfAOs7LJLQX9Fjm0mZ+TSFphD/mKwA== + version "10.0.4" + resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-10.0.4.tgz#f40fcf05f3ee95e7a34bbdcb4dff99da41f0238f" + integrity sha512-Ubs7O3wj2prghaKRa68VHBvuy3KnTQ0zbGwqDYY1mntxJD0QL2AeiAy+AMfl3HBedTCVr2IcFNktwty9YpSskA== dependencies: - "@csstools/cascade-layer-name-parser" "^1.0.8" - "@csstools/css-parser-algorithms" "^2.6.0" - "@csstools/css-tokenizer" "^2.2.3" - "@csstools/media-query-list-parser" "^2.1.8" + "@csstools/cascade-layer-name-parser" "^1.0.9" + "@csstools/css-parser-algorithms" "^2.6.1" + "@csstools/css-tokenizer" "^2.2.4" + "@csstools/media-query-list-parser" "^2.1.9" postcss-custom-properties@^13.3.2: - version "13.3.5" - resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-13.3.5.tgz#0083841407dbf93c833457ecffdf1a3d74a76d10" - integrity sha512-xHg8DTCMfN2nrqs2CQTF+0m5jgnzKL5zrW5Y05KF6xBRO0uDPxiplBm/xcr1o49SLbyJXkMuaRJKhRzkrquKnQ== + version "13.3.8" + resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-13.3.8.tgz#2a75e867fb7a6037e10282e313f9e87ae8881a10" + integrity sha512-OP9yj4yXxYOiW2n2TRpnE7C0yePvBiZb72S22mZVNzZEObdTYFjNaX6oZO4R4E8Ie9RmC/Jxw8EKYSbLrC1EFA== dependencies: - "@csstools/cascade-layer-name-parser" "^1.0.8" - "@csstools/css-parser-algorithms" "^2.6.0" - "@csstools/css-tokenizer" "^2.2.3" + "@csstools/cascade-layer-name-parser" "^1.0.9" + "@csstools/css-parser-algorithms" "^2.6.1" + "@csstools/css-tokenizer" "^2.2.4" "@csstools/utilities" "^1.0.0" postcss-value-parser "^4.2.0" postcss-custom-selectors@^7.1.6: - version "7.1.7" - resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-7.1.7.tgz#66b7adb9a3470ba11860ad7847947c7fd29e985d" - integrity sha512-N19MpExaR+hYTXU59VO02xE42zLoAUYSVcupwkKlWWLteOb+sWCWHw5FhV7u7gVLTzaGULy7nZP3DNTHgOZAPA== + version "7.1.8" + resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-7.1.8.tgz#600ce32a487737038831bb679e9a8011ffc62ee5" + integrity sha512-fqDkGSEsO7+oQaqdRdR8nwwqH+N2uk6LE/2g4myVJJYz/Ly418lHKEleKTdV/GzjBjFcG4n0dbfuH/Pd2BE8YA== dependencies: - "@csstools/cascade-layer-name-parser" "^1.0.8" - "@csstools/css-parser-algorithms" "^2.6.0" - "@csstools/css-tokenizer" "^2.2.3" + "@csstools/cascade-layer-name-parser" "^1.0.9" + "@csstools/css-parser-algorithms" "^2.6.1" + "@csstools/css-tokenizer" "^2.2.4" postcss-selector-parser "^6.0.13" postcss-dir-pseudo-class@^8.0.0: @@ -15504,11 +15962,11 @@ postcss-discard-overridden@^4.0.1: postcss "^7.0.0" postcss-double-position-gradients@^5.0.2: - version "5.0.4" - resolved "https://registry.yarnpkg.com/postcss-double-position-gradients/-/postcss-double-position-gradients-5.0.4.tgz#294787043e5e6187b5489ee52950ecfb303f9ea9" - integrity sha512-xOH2QhazCPeYR+ziYaDcGlpo7Bpw8PVoggOFfU/xPkmBRUQH8MR2eWoPY1CZM93CB0WKs2mxq3ORo83QGIooLw== + version "5.0.6" + resolved "https://registry.yarnpkg.com/postcss-double-position-gradients/-/postcss-double-position-gradients-5.0.6.tgz#fec69371a131b67ec92740bcf8c9ad6ce7f168d3" + integrity sha512-QJ+089FKMaqDxOhhIHsJrh4IP7h4PIHNC5jZP5PMmnfUScNu8Hji2lskqpFWCvu+5sj+2EJFyzKd13sLEWOZmQ== dependencies: - "@csstools/postcss-progressive-custom-properties" "^3.1.0" + "@csstools/postcss-progressive-custom-properties" "^3.2.0" "@csstools/utilities" "^1.0.0" postcss-value-parser "^4.2.0" @@ -15577,14 +16035,14 @@ postcss-jsx@^0.36.3: "@babel/core" ">=7.2.2" postcss-lab-function@^6.0.7: - version "6.0.10" - resolved "https://registry.yarnpkg.com/postcss-lab-function/-/postcss-lab-function-6.0.10.tgz#efe1bbf9fa1f1034890a0ad078286bfbace11106" - integrity sha512-Csvw/CwwuwTojK2O3Ad0SvYKrfnAKy+uvT+1Fjk6igR+n8gHuJHIwdj1A2s46EZZojg3RkibdMBuv1vMvR6Sng== - dependencies: - "@csstools/css-color-parser" "^1.5.2" - "@csstools/css-parser-algorithms" "^2.6.0" - "@csstools/css-tokenizer" "^2.2.3" - "@csstools/postcss-progressive-custom-properties" "^3.1.0" + version "6.0.14" + resolved "https://registry.yarnpkg.com/postcss-lab-function/-/postcss-lab-function-6.0.14.tgz#ccc4dec33e01cae3a435b45de2f29b455286ea10" + integrity sha512-ddQS9FRWT8sfl4wfW0ae8fpP2JdLIuhC9pYpHq1077avjrLzg73T9IEVu5QmFa72nJhYFlO9CbqjcoSdEzfY9A== + dependencies: + "@csstools/css-color-parser" "^2.0.0" + "@csstools/css-parser-algorithms" "^2.6.1" + "@csstools/css-tokenizer" "^2.2.4" + "@csstools/postcss-progressive-custom-properties" "^3.2.0" "@csstools/utilities" "^1.0.0" postcss-less@^3.1.4: @@ -15721,11 +16179,12 @@ postcss-modules-values@^3.0.0: postcss "^7.0.6" postcss-nesting@^12.0, postcss-nesting@^12.0.1: - version "12.0.4" - resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-12.0.4.tgz#593d577fd1fbbfbe0997a6c81dbff074b26c83a2" - integrity sha512-WuCe0KnP4vKjLZK8VNoUWKL8ZLOv/5jiM94mHcI3VszLropHwmjotdUyP/ObzqZpXuQKP2Jf9R12vIHKFSStKw== + version "12.1.2" + resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-12.1.2.tgz#e7aba3f73b86a0e944e84798d481b54dcfce802e" + integrity sha512-FUmTHGDNundodutB4PUBxt/EPuhgtpk8FJGRsBhOuy+6FnkR2A8RZWIsyyy6XmhvX2DZQQWIkvu+HB4IbJm+Ew== dependencies: - "@csstools/selector-specificity" "^3.0.2" + "@csstools/selector-resolve-nested" "^1.1.0" + "@csstools/selector-specificity" "^3.0.3" postcss-selector-parser "^6.0.13" postcss-normalize-charset@^4.0.1: @@ -15909,9 +16368,9 @@ postcss-preset-env@9.3.0: postcss-value-parser "^4.2.0" postcss-pseudo-class-any-link@^9.0.0: - version "9.0.1" - resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-9.0.1.tgz#71c24a886765763d4e37e21a27ecc6f1c1a5d698" - integrity sha512-cKYGGZ9yzUZi+dZd7XT2M8iSDfo+T2Ctbpiizf89uBTBfIpZpjvTavzIJXpCReMVXSKROqzpxClNu6fz4DHM0Q== + version "9.0.2" + resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-9.0.2.tgz#e436a7db1421f8a347fff3f19951a27d4e791987" + integrity sha512-HFSsxIqQ9nA27ahyfH37cRWGk3SYyQLpk0LiWw/UGMV4VKT5YG2ONee4Pz/oFesnK0dn2AjcyequDbIjKJgB0g== dependencies: postcss-selector-parser "^6.0.13" @@ -15994,9 +16453,9 @@ postcss-selector-parser@^3.0.0, postcss-selector-parser@^3.1.0: uniq "^1.0.1" postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.13, postcss-selector-parser@^6.0.2: - version "6.0.15" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz#11cc2b21eebc0b99ea374ffb9887174855a01535" - integrity sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw== + version "6.0.16" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz#3b88b9f5c5abd989ef4e2fc9ec8eedd34b20fb04" + integrity sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw== dependencies: cssesc "^3.0.0" util-deprecate "^1.0.2" @@ -16069,14 +16528,14 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.2, postcss@^7.0.21 picocolors "^0.2.1" source-map "^0.6.1" -postcss@^8.1.7, postcss@^8.4, postcss@^8.4.32, postcss@^8.4.35: - version "8.4.35" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.35.tgz#60997775689ce09011edf083a549cea44aabe2f7" - integrity sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA== +postcss@^8.1.7, postcss@^8.4, postcss@^8.4.32, postcss@^8.4.38: + version "8.4.38" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.38.tgz#b387d533baf2054288e337066d81c6bee9db9e0e" + integrity sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A== dependencies: nanoid "^3.3.7" picocolors "^1.0.0" - source-map-js "^1.0.2" + source-map-js "^1.2.0" precinct@^6.3.1: version "6.3.1" @@ -16122,7 +16581,7 @@ prettier@^2.8.0: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== -pretty-bytes@^5.4.1: +pretty-bytes@^5.6.0: version "5.6.0" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== @@ -16222,11 +16681,6 @@ property-expr@^2.0.4, property-expr@^2.0.5: resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.6.tgz#f77bc00d5928a6c748414ad12882e83f24aec1e8" integrity sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA== -property-information@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/property-information/-/property-information-3.2.0.tgz#fd1483c8fbac61808f5fe359e7693a1f48a58331" - integrity sha512-BKU45RMZAA+3npkQ/VxEH7EeZImQcfV6rfKH0O4HkkDz3uqqz+689dbkjiWia00vK390MY6EARPS6TzNS4tXPg== - property-information@^5.0.0, property-information@^5.2.0: version "5.6.0" resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69" @@ -16234,6 +16688,11 @@ property-information@^5.0.0, property-information@^5.2.0: dependencies: xtend "^4.0.0" +property-information@^6.0.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.5.0.tgz#6212fbb52ba757e92ef4fb9d657563b933b7ffec" + integrity sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig== + proxy-addr@~2.0.4, proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -16242,6 +16701,11 @@ proxy-addr@~2.0.4, proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" +proxy-from-env@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" + integrity sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A== + proxy-from-env@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" @@ -16356,6 +16820,13 @@ qap@^3.1.2: resolved "https://registry.yarnpkg.com/qap/-/qap-3.3.1.tgz#11f9e8fa8890fe7cb99210c0f44d0613b7372cac" integrity sha512-U0MV9LRz4u19xaK4gssnwyc7XWTnFdmDGrgG9hvV6nchKeu3XeITTclugWKT9rLiLK2GvN3utSkKY90+1tEHkw== +qs@6.10.4: + version "6.10.4" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.4.tgz#6a3003755add91c0ec9eacdc5f878b034e73f9e7" + integrity sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g== + dependencies: + side-channel "^1.0.4" + qs@6.11.0: version "6.11.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" @@ -16369,18 +16840,11 @@ qs@6.5.2: integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== qs@^6.10.0, qs@^6.11.2: - version "6.11.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" - integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== + version "6.12.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.12.1.tgz#39422111ca7cbdb70425541cba20c7d7b216599a" + integrity sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ== dependencies: - side-channel "^1.0.4" - -qs@~6.10.3: - version "6.10.5" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.5.tgz#974715920a80ff6a262264acd2c7e6c2a53282b4" - integrity sha512-O5RlPh0VFtR78y79rgcgKK4wbAI0C5zGVLztOIdpWX6ep368q5Hv6XRxDvXuZ9q3C6v+e3n8UfZZJw7IIG27eQ== - dependencies: - side-channel "^1.0.4" + side-channel "^1.0.6" qs@~6.5.2: version "6.5.3" @@ -16457,11 +16921,6 @@ ramda@0.29.0: resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.29.0.tgz#fbbb67a740a754c8a4cbb41e2a6e0eb8507f55fb" integrity sha512-BBea6L67bYLtdbOqfp8f58fPMqEwx0doL+pAi8TZyp2YWz8R9G8z9x75CZI8W+ftqhFHCpEX2cRnUUXK130iKA== -ramda@~0.27.1: - version "0.27.2" - resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.27.2.tgz#84463226f7f36dc33592f6f4ed6374c48306c3f1" - integrity sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA== - randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -16654,6 +17113,22 @@ react-is@^18.0.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== +react-markdown@9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-9.0.1.tgz#c05ddbff67fd3b3f839f8c648e6fb35d022397d1" + integrity sha512-186Gw/vF1uRkydbsOIkcGXw7aHq0sZOCRFFjGrr7b9+nVZg4UfA4enXCaxm4fUzecU38sWfrNDitGhshuU7rdg== + dependencies: + "@types/hast" "^3.0.0" + devlop "^1.0.0" + hast-util-to-jsx-runtime "^2.0.0" + html-url-attributes "^3.0.0" + mdast-util-to-hast "^13.0.0" + remark-parse "^11.0.0" + remark-rehype "^11.0.0" + unified "^11.0.0" + unist-util-visit "^5.0.0" + vfile "^6.0.0" + react-popper@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-1.0.0.tgz#b99452144e8fe4acc77fa3d959a8c79e07a65084" @@ -16693,9 +17168,9 @@ react-refresh@^0.14.0: integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ== react-remove-scroll-bar@^2.1.0, react-remove-scroll-bar@^2.3.3: - version "2.3.5" - resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.5.tgz#cd2543b3ed7716c7c5b446342d21b0e0b303f47c" - integrity sha512-3cqjOqg6s0XbOjWvmasmqHch+RLxIEk2r/70rzGXuz3iIGQsQheEQyqYCBb5EECoD01Vo2SIbDqW4paLeLTASw== + version "2.3.6" + resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz#3e585e9d163be84a010180b18721e851ac81a29c" + integrity sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g== dependencies: react-style-singleton "^2.2.1" tslib "^2.0.0" @@ -16764,9 +17239,9 @@ react-select@5.4.0: react-transition-group "^4.3.0" react-simple-keyboard@^3.7.0: - version "3.7.107" - resolved "https://registry.yarnpkg.com/react-simple-keyboard/-/react-simple-keyboard-3.7.107.tgz#6e71f48950a1923486f2ca8edc5194cdbae0f332" - integrity sha512-r2emrLGoD6A37fl+GCEODFLxtUET1uXZsmFokb7cB6/3OlE7EV08wSzB+yTju+qwIibsc6EXLC6KoRf0FsVC1A== + version "3.7.114" + resolved "https://registry.yarnpkg.com/react-simple-keyboard/-/react-simple-keyboard-3.7.114.tgz#7cd09474d90ed92d4ee05b462e160dd9cf16a13c" + integrity sha512-4CxIzJJx3sHqYqLZdjXmKR6LcGaYC4SEa/rWd2u5PxEJsG5adw4KWjhKSQvxUZDWMhL3Fe+WDMW02O9JcWawiA== react-snap@^1.23.0: version "1.23.0" @@ -16884,7 +17359,7 @@ read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@^2.3.8, readable-stream@~2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -16907,7 +17382,7 @@ readable-stream@1.1.x: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0, readable-stream@^3.6.2: +readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== @@ -16933,9 +17408,9 @@ readdirp@~3.6.0: picomatch "^2.2.1" recast@^0.23.1, recast@^0.23.3: - version "0.23.5" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.23.5.tgz#07f5594a0d36e7754356160b70e90393cca0406d" - integrity sha512-M67zIddJiwXdfPQRYKJ0qZO1SLdH1I0hYeb0wzxA+pNOvAZiQHulWzuk+fYsEWRQ8VfZrgjyucqsCOtCyM01/A== + version "0.23.6" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.23.6.tgz#198fba74f66143a30acc81929302d214ce4e3bfa" + integrity sha512-9FHoNjX1yjuesMwuthAmPKabxYQdOgihFYmT5ebXfYGBcnqXZf3WOVz+5foEZ8Y83P4ZY6yQD5GMmtV+pgCCAQ== dependencies: ast-types "^0.16.1" esprima "~4.0.0" @@ -17014,15 +17489,15 @@ redux@^4.0.0, redux@^4.0.5, redux@^4.2.0: "@babel/runtime" "^7.9.2" reflect.getprototypeof@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.5.tgz#e0bd28b597518f16edaf9c0e292c631eb13e0674" - integrity sha512-62wgfC8dJWrmxv44CA36pLDnP6KKl3Vhxb7PL+8+qrrFMMoJij4vgiMP8zV4O8+CBMXY1mHxI5fITGHXFHVmQQ== + version "1.0.6" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz#3ab04c32a8390b770712b7a8633972702d278859" + integrity sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg== dependencies: - call-bind "^1.0.5" + call-bind "^1.0.7" define-properties "^1.2.1" - es-abstract "^1.22.3" - es-errors "^1.0.0" - get-intrinsic "^1.2.3" + es-abstract "^1.23.1" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" globalthis "^1.0.3" which-builtin-type "^1.1.3" @@ -17063,7 +17538,7 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexp.prototype.flags@^1.5.0, regexp.prototype.flags@^1.5.1, regexp.prototype.flags@^1.5.2: +regexp.prototype.flags@^1.5.1, regexp.prototype.flags@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== @@ -17148,26 +17623,15 @@ remark-external-links@^8.0.0: space-separated-tokens "^1.0.0" unist-util-visit "^2.0.0" -remark-parse@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-5.0.0.tgz#4c077f9e499044d1d5c13f80d7a98cf7b9285d95" - integrity sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA== +remark-parse@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-11.0.0.tgz#aa60743fcb37ebf6b069204eb4da304e40db45a1" + integrity sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA== dependencies: - collapse-white-space "^1.0.2" - is-alphabetical "^1.0.0" - is-decimal "^1.0.0" - is-whitespace-character "^1.0.0" - is-word-character "^1.0.0" - markdown-escapes "^1.0.0" - parse-entities "^1.1.0" - repeat-string "^1.5.4" - state-toggle "^1.0.0" - trim "0.0.1" - trim-trailing-lines "^1.0.0" - unherit "^1.0.4" - unist-util-remove-position "^1.0.0" - vfile-location "^2.0.0" - xtend "^4.0.1" + "@types/mdast" "^4.0.0" + mdast-util-from-markdown "^2.0.0" + micromark-util-types "^2.0.0" + unified "^11.0.0" remark-parse@^6.0.0: version "6.0.3" @@ -17190,15 +17654,16 @@ remark-parse@^6.0.0: vfile-location "^2.0.0" xtend "^4.0.1" -remark-react@4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/remark-react/-/remark-react-4.0.3.tgz#980938f3bcc93bef220215b26b0b0a80f3158c7d" - integrity sha512-M2DxXfX8/GK0hV84PUcsvkvb+8yGLdV+krb8mW28eoa9ZgTrhC5rk01EPRMXRNGCAEl3JMDFs+VKdT/FbsN9vg== +remark-rehype@^11.0.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-11.1.0.tgz#d5f264f42bcbd4d300f030975609d01a1697ccdc" + integrity sha512-z3tJrAs2kIs1AqIIy6pzHmAHlF1hWQ+OdY4/hv+Wxe35EhyLKcajL33iUEn3ScxtFox9nUvRufR/Zre8Q08H/g== dependencies: - "@mapbox/hast-util-table-cell-style" "^0.1.3" - hast-to-hyperscript "^4.0.0" - hast-util-sanitize "^1.0.0" - mdast-util-to-hast "^3.0.0" + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + mdast-util-to-hast "^13.0.0" + unified "^11.0.0" + vfile "^6.0.0" remark-slug@^6.0.0: version "6.1.0" @@ -17209,26 +17674,6 @@ remark-slug@^6.0.0: mdast-util-to-string "^1.0.0" unist-util-visit "^2.0.0" -remark-stringify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-5.0.0.tgz#336d3a4d4a6a3390d933eeba62e8de4bd280afba" - integrity sha512-Ws5MdA69ftqQ/yhRF9XhVV29mhxbfGhbz0Rx5bQH+oJcNhhSM6nCu1EpLod+DjrFGrU0BMPs+czVmJZU7xiS7w== - dependencies: - ccount "^1.0.0" - is-alphanumeric "^1.0.0" - is-decimal "^1.0.0" - is-whitespace-character "^1.0.0" - longest-streak "^2.0.1" - markdown-escapes "^1.0.0" - markdown-table "^1.1.0" - mdast-util-compact "^1.0.0" - parse-entities "^1.0.2" - repeat-string "^1.5.4" - state-toggle "^1.0.0" - stringify-entities "^1.0.1" - unherit "^1.0.4" - xtend "^4.0.1" - remark-stringify@^6.0.0: version "6.0.4" resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-6.0.4.tgz#16ac229d4d1593249018663c7bddf28aafc4e088" @@ -17249,15 +17694,6 @@ remark-stringify@^6.0.0: unherit "^1.0.4" xtend "^4.0.1" -remark@9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/remark/-/remark-9.0.0.tgz#c5cfa8ec535c73a67c4b0f12bfdbd3a67d8b2f60" - integrity sha512-amw8rGdD5lHbMEakiEsllmkdBP+/KpjW/PRK6NSGPZKCQowh0BT4IWXDAkRMyG3SB9dKPXWMviFjNusXzXNn3A== - dependencies: - remark-parse "^5.0.0" - remark-stringify "^5.0.0" - unified "^6.0.0" - remark@^10.0.1: version "10.0.1" resolved "https://registry.yarnpkg.com/remark/-/remark-10.0.1.tgz#3058076dc41781bf505d8978c291485fe47667df" @@ -17483,22 +17919,6 @@ responselike@^2.0.0: dependencies: lowercase-keys "^2.0.0" -restore-cursor@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" - integrity sha512-reSjH4HuiFlxlaBaFCiS6O76ZGG2ygKoSlCsipKdaZuKSPx/+bt9mULkn4l0asVzbEfQQmXRg6Wp6gv6m0wElw== - dependencies: - exit-hook "^1.0.0" - onetime "^1.0.0" - -restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q== - dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" - restore-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" @@ -17612,26 +18032,29 @@ rollup@^2.44.0: optionalDependencies: fsevents "~2.3.2" -rollup@^4.2.0: - version "4.12.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.12.0.tgz#0b6d1e5f3d46bbcf244deec41a7421dc54cc45b5" - integrity sha512-wz66wn4t1OHIJw3+XU7mJJQV/2NAfw5OAk6G6Hoo3zcvz/XOfQ52Vgi+AN4Uxoxi0KBBwk2g8zPrTDA4btSB/Q== +rollup@^4.13.0, rollup@^4.2.0: + version "4.16.2" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.16.2.tgz#43bcbd225d0a6bc68df97a6e41c45003188a3845" + integrity sha512-sxDP0+pya/Yi5ZtptF4p3avI+uWCIf/OdrfdH2Gbv1kWddLKk0U7WE3PmQokhi5JrektxsK3sK8s4hzAmjqahw== dependencies: "@types/estree" "1.0.5" optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.12.0" - "@rollup/rollup-android-arm64" "4.12.0" - "@rollup/rollup-darwin-arm64" "4.12.0" - "@rollup/rollup-darwin-x64" "4.12.0" - "@rollup/rollup-linux-arm-gnueabihf" "4.12.0" - "@rollup/rollup-linux-arm64-gnu" "4.12.0" - "@rollup/rollup-linux-arm64-musl" "4.12.0" - "@rollup/rollup-linux-riscv64-gnu" "4.12.0" - "@rollup/rollup-linux-x64-gnu" "4.12.0" - "@rollup/rollup-linux-x64-musl" "4.12.0" - "@rollup/rollup-win32-arm64-msvc" "4.12.0" - "@rollup/rollup-win32-ia32-msvc" "4.12.0" - "@rollup/rollup-win32-x64-msvc" "4.12.0" + "@rollup/rollup-android-arm-eabi" "4.16.2" + "@rollup/rollup-android-arm64" "4.16.2" + "@rollup/rollup-darwin-arm64" "4.16.2" + "@rollup/rollup-darwin-x64" "4.16.2" + "@rollup/rollup-linux-arm-gnueabihf" "4.16.2" + "@rollup/rollup-linux-arm-musleabihf" "4.16.2" + "@rollup/rollup-linux-arm64-gnu" "4.16.2" + "@rollup/rollup-linux-arm64-musl" "4.16.2" + "@rollup/rollup-linux-powerpc64le-gnu" "4.16.2" + "@rollup/rollup-linux-riscv64-gnu" "4.16.2" + "@rollup/rollup-linux-s390x-gnu" "4.16.2" + "@rollup/rollup-linux-x64-gnu" "4.16.2" + "@rollup/rollup-linux-x64-musl" "4.16.2" + "@rollup/rollup-win32-arm64-msvc" "4.16.2" + "@rollup/rollup-win32-ia32-msvc" "4.16.2" + "@rollup/rollup-win32-x64-msvc" "4.16.2" fsevents "~2.3.2" run-parallel@^1.1.9: @@ -17648,27 +18071,27 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" -rxjs@^6.3.3, rxjs@^6.5.1, rxjs@^6.5.5: +rxjs@^6.5.1, rxjs@^6.5.5: version "6.6.7" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== dependencies: tslib "^1.9.0" -rxjs@^7.8.1: +rxjs@^7.5.1, rxjs@^7.8.1: version "7.8.1" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== dependencies: tslib "^2.1.0" -safe-array-concat@^1.0.0, safe-array-concat@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.0.tgz#8d0cae9cb806d6d1c06e08ab13d847293ebe0692" - integrity sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg== +safe-array-concat@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" + integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== dependencies: - call-bind "^1.0.5" - get-intrinsic "^1.2.2" + call-bind "^1.0.7" + get-intrinsic "^1.2.4" has-symbols "^1.0.3" isarray "^2.0.5" @@ -17968,18 +18391,18 @@ set-blocking@^2.0.0: integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== set-function-length@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.1.tgz#47cc5945f2c771e2cf261c6737cf9684a2a5e425" - integrity sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g== + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== dependencies: - define-data-property "^1.1.2" + define-data-property "^1.1.4" es-errors "^1.3.0" function-bind "^1.1.2" - get-intrinsic "^1.2.3" + get-intrinsic "^1.2.4" gopd "^1.0.1" - has-property-descriptors "^1.0.1" + has-property-descriptors "^1.0.2" -set-function-name@^2.0.0, set-function-name@^2.0.1: +set-function-name@^2.0.1, set-function-name@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== @@ -18085,7 +18508,7 @@ shx@^0.3.3: minimist "^1.2.3" shelljs "^0.8.5" -side-channel@^1.0.4: +side-channel@^1.0.4, side-channel@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== @@ -18111,9 +18534,9 @@ signal-exit@^4.0.1, signal-exit@^4.1.0: integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== simple-git@^3.15.1: - version "3.22.0" - resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-3.22.0.tgz#616d41c661e30f9c65778956317d422b1729a242" - integrity sha512-6JujwSs0ac82jkGjMHiCnTifvf1crOiY/+tfs/Pqih6iow7VrpNKRRNdWm6RtaXpvvv/JGNYhlUtLhGFqHF+Yw== + version "3.24.0" + resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-3.24.0.tgz#33a8c88dc6fa74e53eaf3d6bfc27d0182a49ec00" + integrity sha512-QqAKee9Twv+3k8IFOFfPB2hnk6as6Y6ACUpwCtQvRYBAes23Wv3SZlHVobAzqcE8gfsisCvPw3HGW3HYM+VYYw== dependencies: "@kwsites/file-exists" "^1.1.1" "@kwsites/promise-deferred" "^1.1.1" @@ -18148,11 +18571,6 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -slice-ansi@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" - integrity sha512-up04hB2hR92PgjpyU3y/eg91yIBILyjVY26NvvciY3EVVPjybkMszMpXQ9QAkcS3I5rtJBDLoTxxg+qvW8c7rw== - slice-ansi@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" @@ -18171,6 +18589,15 @@ slice-ansi@^3.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + smart-buffer@^4.0.2, smart-buffer@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" @@ -18236,9 +18663,9 @@ socks-proxy-agent@^7.0.0: socks "^2.6.2" socks@^2.6.2: - version "2.8.1" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.1.tgz#22c7d9dd7882649043cba0eafb49ae144e3457af" - integrity sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ== + version "2.8.3" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.3.tgz#1ebd0f09c52ba95a09750afe3f3f9f724a800cb5" + integrity sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw== dependencies: ip-address "^9.0.5" smart-buffer "^4.2.0" @@ -18269,10 +18696,10 @@ source-list-map@^2.0.0: resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== -source-map-js@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" - integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== +source-map-js@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" + integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== source-map-resolve@^0.5.0: version "0.5.3" @@ -18327,6 +18754,11 @@ space-separated-tokens@^1.0.0: resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899" integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA== +space-separated-tokens@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz#1ecd9d2350a3844572c3f4a312bceb018348859f" + integrity sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q== + spawn-command@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2.tgz#9544e1a43ca045f8531aac1a48cb29bdae62338e" @@ -18575,7 +19007,7 @@ stream-http@^2.7.2: to-arraybuffer "^1.0.0" xtend "^4.0.0" -stream-shift@^1.0.0: +stream-shift@^1.0.0, stream-shift@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.3.tgz#85b8fab4d71010fc3ba8772e8046cc49b8a3864b" integrity sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ== @@ -18604,23 +19036,6 @@ strict-uri-encode@^2.0.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw== - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -string-width@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - string-width@^3.0.0, string-width@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" @@ -18640,46 +19055,50 @@ string-width@^5.0.1, string-width@^5.1.2: strip-ansi "^7.0.1" string.prototype.matchall@^4.0.10: - version "4.0.10" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz#a1553eb532221d4180c51581d6072cd65d1ee100" - integrity sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ== + version "4.0.11" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz#1092a72c59268d2abaad76582dccc687c0297e0a" + integrity sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" + gopd "^1.0.1" has-symbols "^1.0.3" - internal-slot "^1.0.5" - regexp.prototype.flags "^1.5.0" - set-function-name "^2.0.0" - side-channel "^1.0.4" + internal-slot "^1.0.7" + regexp.prototype.flags "^1.5.2" + set-function-name "^2.0.2" + side-channel "^1.0.6" -string.prototype.trim@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" - integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== +string.prototype.trim@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" + integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.0" + es-object-atoms "^1.0.0" -string.prototype.trimend@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e" - integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== +string.prototype.trimend@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" + integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" -string.prototype.trimstart@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298" - integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" string_decoder@^1.0.0, string_decoder@^1.1.1: version "1.3.0" @@ -18721,6 +19140,14 @@ stringify-entities@^2.0.0: is-decimal "^1.0.2" is-hexadecimal "^1.0.0" +stringify-entities@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/stringify-entities/-/stringify-entities-4.0.4.tgz#b3b79ef5f277cc4ac73caeb0236c5ba939b3a4f3" + integrity sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg== + dependencies: + character-entities-html4 "^2.0.0" + character-entities-legacy "^3.0.0" + stringify-object@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" @@ -18744,13 +19171,6 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1: dependencies: ansi-regex "^2.0.0" -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow== - dependencies: - ansi-regex "^3.0.0" - strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -18848,6 +19268,13 @@ style-search@^0.1.0: resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902" integrity sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg== +style-to-object@^1.0.0: + version "1.0.6" + resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-1.0.6.tgz#0c28aed8be1813d166c60d962719b2907c26547b" + integrity sha512-khxq+Qm3xEyZfKd/y9L3oIWQimxuc4STrQKtQn8aSDRHb8mFgpukgX1hdzfrMEW6JCjyJ8p89x+IUMVnCBI1PA== + dependencies: + inline-style-parser "0.2.3" + styled-components@5.3.6: version "5.3.6" resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.3.6.tgz#27753c8c27c650bee9358e343fc927966bfd00d1" @@ -19000,7 +19427,7 @@ supports-color@^6.1.0: dependencies: has-flag "^3.0.0" -supports-color@^7.0.0, supports-color@^7.1.0, supports-color@^7.2.0: +supports-color@^7.0.0, supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== @@ -19043,7 +19470,7 @@ svgo@^1.0.0: unquote "~1.1.1" util.promisify "~1.0.0" -symbol-observable@^1.1.0, symbol-observable@^1.2.0: +symbol-observable@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== @@ -19108,9 +19535,9 @@ tar-stream@^2.1.4: readable-stream "^3.1.1" tar@^6.0.5, tar@^6.1.11, tar@^6.1.12, tar@^6.1.2, tar@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.0.tgz#b14ce49a79cb1cd23bc9b016302dea5474493f73" - integrity sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ== + version "6.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" + integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== dependencies: chownr "^2.0.0" fs-minipass "^2.0.0" @@ -19202,9 +19629,9 @@ terser@^4.1.2, terser@^4.6.12: source-map-support "~0.5.12" terser@^5.0.0: - version "5.28.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.28.1.tgz#bf00f7537fd3a798c352c2d67d67d65c915d1b28" - integrity sha512-wM+bZp54v/E9eRRGXb5ZFDvinrJIOaTapx3WUokyVGZu5ucVCK55zEgGd5Dl2fSr3jUo5sDiERErUWLY6QPFyA== + version "5.30.4" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.30.4.tgz#62b4d16a819424e6317fd5ceffb4ee8dc769803a" + integrity sha512-xRdd0v64a8mFK9bnsKVdoNP9GQIKUAaJPTaqEQDL4w/J8WaW4sWXXoMZ+6SimPkfT5bElreXf8m9HnmPc3E1BQ== dependencies: "@jridgewell/source-map" "^0.3.3" acorn "^8.8.2" @@ -19298,9 +19725,9 @@ tiny-warning@^1.0.0, tiny-warning@^1.0.2: integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== tinybench@^2.5.1: - version "2.6.0" - resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.6.0.tgz#1423284ee22de07c91b3752c048d2764714b341b" - integrity sha512-N8hW3PG/3aOoZAN5V/NSAEDz0ZixDSSt5b/a05iqtpgfLWMSVuCo7w0k2vVvEjdrIoeGqZzweX2WlyioNIHchA== + version "2.8.0" + resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.8.0.tgz#30e19ae3a27508ee18273ffed9ac7018949acd7b" + integrity sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw== tinycolor2@^1.4.1: version "1.6.0" @@ -19308,9 +19735,9 @@ tinycolor2@^1.4.1: integrity sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw== tinypool@^0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.8.2.tgz#84013b03dc69dacb322563a475d4c0a9be00f82a" - integrity sha512-SUszKYe5wgsxnNOVlBYO6IC+8VGWdVGZWAqUxp3UErNBtptZvWbwyUOyzNL59zigz2rCA92QiL3wvG+JDSdJdQ== + version "0.8.4" + resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.8.4.tgz#e217fe1270d941b39e98c625dcecebb1408c9aa8" + integrity sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ== tinyspy@^2.2.0: version "2.2.1" @@ -19382,9 +19809,9 @@ to-regex@3.0.2, to-regex@^3.0.1, to-regex@^3.0.2: safe-regex "^1.1.0" tocbot@^4.20.1: - version "4.25.0" - resolved "https://registry.yarnpkg.com/tocbot/-/tocbot-4.25.0.tgz#bc38aea5ec8f076779bb39636f431b044129a237" - integrity sha512-kE5wyCQJ40hqUaRVkyQ4z5+4juzYsv/eK+aqD97N62YH0TxFhzJvo22RUQQZdO3YnXAk42ZOfOpjVdy+Z0YokA== + version "4.27.0" + resolved "https://registry.yarnpkg.com/tocbot/-/tocbot-4.27.0.tgz#8215d50df66dc6e3b86c8f7b10389b2d6b8bd555" + integrity sha512-x3ZPNFPVOYCAyW4CEW8KszGfqB3/fnY1QX1tfUHH1fj1r6I8v0g5w0flNsWf7htZKtzqtdiPqu//II3ngL/WwA== toidentifier@1.0.1: version "1.0.1" @@ -19441,10 +19868,10 @@ tree-kill@^1.2.2: resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== -trim-lines@^1.0.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/trim-lines/-/trim-lines-1.1.3.tgz#839514be82428fd9e7ec89e35081afe8f6f93115" - integrity sha512-E0ZosSWYK2mkSu+KEtQ9/KqarVjA9HztOSX+9FDdNacRAq29RRV6ZQNgob3iuW8Htar9vAfEa6yyt5qBAHZDBA== +trim-lines@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/trim-lines/-/trim-lines-3.0.1.tgz#d802e332a07df861c48802c04321017b1bd87338" + integrity sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg== trim-newlines@^2.0.0: version "2.0.0" @@ -19483,6 +19910,11 @@ trough@^1.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== +trough@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/trough/-/trough-2.2.0.tgz#94a60bd6bd375c152c1df911a4b11d5b0256f50f" + integrity sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw== + truncate-utf8-bytes@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz#405923909592d56f78a5818434b0b78489ca5f2b" @@ -19496,9 +19928,9 @@ tryer@^1.0.1: integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== ts-api-utils@^1.0.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.2.1.tgz#f716c7e027494629485b21c0df6180f4d08f5e8b" - integrity sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA== + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== ts-dedent@^2.0.0, ts-dedent@^2.2.0: version "2.2.0" @@ -19581,6 +20013,11 @@ type-fest@^0.20.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + type-fest@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" @@ -19641,10 +20078,10 @@ typed-array-byte-offset@^1.0.2: has-proto "^1.0.3" is-typed-array "^1.1.13" -typed-array-length@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.5.tgz#57d44da160296d8663fd63180a1802ebf25905d5" - integrity sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA== +typed-array-length@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" + integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== dependencies: call-bind "^1.0.7" for-each "^0.3.3" @@ -19675,7 +20112,7 @@ typeface-open-sans@0.0.75: resolved "https://registry.yarnpkg.com/typeface-open-sans/-/typeface-open-sans-0.0.75.tgz#20d0c330f14c0c40463c334adbedd6005389abe4" integrity sha512-0lLmB7pfj113OP4T78SbpSmC4OCdFQ0vUxdSXQccsSb6qF76F92iEuC/DghFgmPswTyidk8+Hwf+PS/htiJoRQ== -typescript@5.3.3, typescript@^5.3.3: +typescript@5.3.3: version "5.3.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37" integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw== @@ -19685,15 +20122,20 @@ typescript@^3.0.3, typescript@^3.8.3, typescript@^3.9.5, typescript@^3.9.7: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8" integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q== +typescript@^5.3.3: + version "5.4.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611" + integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ== + ua-parser-js@^0.7.23, ua-parser-js@^0.7.30: version "0.7.37" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.37.tgz#e464e66dac2d33a7a1251d7d7a99d6157ec27832" integrity sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA== ufo@^1.3.2, ufo@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.4.0.tgz#39845b31be81b4f319ab1d99fd20c56cac528d32" - integrity sha512-Hhy+BhRBleFjpJ2vchUNN40qgkh0366FWJGqVLYBHev0vpHTrXSA0ryT+74UiW6KWsldNurQMKGqCm1M2zBciQ== + version "1.5.3" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.5.3.tgz#3325bd3c977b6c6cd3160bf4ff52989adc9d3344" + integrity sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw== uglify-js@3.4.x: version "3.4.10" @@ -19762,17 +20204,18 @@ unicode-property-aliases-ecmascript@^2.0.0: resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== -unified@^6.0.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/unified/-/unified-6.2.0.tgz#7fbd630f719126d67d40c644b7e3f617035f6dba" - integrity sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA== +unified@^11.0.0: + version "11.0.4" + resolved "https://registry.yarnpkg.com/unified/-/unified-11.0.4.tgz#f4be0ac0fe4c88cb873687c07c64c49ed5969015" + integrity sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ== dependencies: - bail "^1.0.0" + "@types/unist" "^3.0.0" + bail "^2.0.0" + devlop "^1.0.0" extend "^3.0.0" - is-plain-obj "^1.1.0" - trough "^1.0.0" - vfile "^2.0.0" - x-is-string "^0.1.0" + is-plain-obj "^4.0.0" + trough "^2.0.0" + vfile "^6.0.0" unified@^7.0.0: version "7.1.0" @@ -19854,13 +20297,6 @@ unique-string@^2.0.0: dependencies: crypto-random-string "^2.0.0" -unist-builder@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unist-builder/-/unist-builder-1.0.4.tgz#e1808aed30bd72adc3607f25afecebef4dd59e17" - integrity sha512-v6xbUPP7ILrT15fHGrNyHc1Xda8H3xVhP7/HAIotHOhVPjH5dCXA097C3Rry1Q2O+HbOLCao4hfPB+EYEjHgVg== - dependencies: - object-assign "^4.1.0" - unist-util-find-all-after@^1.0.2: version "1.0.5" resolved "https://registry.yarnpkg.com/unist-util-find-all-after/-/unist-util-find-all-after-1.0.5.tgz#5751a8608834f41d117ad9c577770c5f2f1b2899" @@ -19868,16 +20304,6 @@ unist-util-find-all-after@^1.0.2: dependencies: unist-util-is "^3.0.0" -unist-util-generated@^1.1.0: - version "1.1.6" - resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-1.1.6.tgz#5ab51f689e2992a472beb1b35f2ce7ff2f324d4b" - integrity sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg== - -unist-util-is@^2.0.0: - version "2.1.3" - resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-2.1.3.tgz#459182db31f4742fceaea88d429693cbf0043d20" - integrity sha512-4WbQX2iwfr/+PfM4U3zd2VNXY+dWtZsN1fLnWEi2QQXA4qyDYAZcDMfXUX0Cu6XZUHHAO9q4nyxxLT4Awk1qUA== - unist-util-is@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-3.0.0.tgz#d9e84381c2468e82629e4a5be9d7d05a2dd324cd" @@ -19888,10 +20314,19 @@ unist-util-is@^4.0.0: resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-4.1.0.tgz#976e5f462a7a5de73d94b706bac1b90671b57797" integrity sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg== -unist-util-position@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-3.1.0.tgz#1c42ee6301f8d52f47d14f62bbdb796571fa2d47" - integrity sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA== +unist-util-is@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-6.0.0.tgz#b775956486aff107a9ded971d996c173374be424" + integrity sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw== + dependencies: + "@types/unist" "^3.0.0" + +unist-util-position@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-5.0.0.tgz#678f20ab5ca1207a97d7ea8a388373c9cf896be4" + integrity sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA== + dependencies: + "@types/unist" "^3.0.0" unist-util-remove-position@^1.0.0: version "1.1.4" @@ -19900,6 +20335,14 @@ unist-util-remove-position@^1.0.0: dependencies: unist-util-visit "^1.1.0" +unist-util-remove-position@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz#fea68a25658409c9460408bc6b4991b965b52163" + integrity sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q== + dependencies: + "@types/unist" "^3.0.0" + unist-util-visit "^5.0.0" + unist-util-stringify-position@^1.0.0, unist-util-stringify-position@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz#3f37fcf351279dcbca7480ab5889bb8a832ee1c6" @@ -19934,7 +20377,15 @@ unist-util-visit-parents@^3.0.0: "@types/unist" "^2.0.0" unist-util-is "^4.0.0" -unist-util-visit@^1.0.0, unist-util-visit@^1.1.0, unist-util-visit@^1.3.0, unist-util-visit@^1.4.0: +unist-util-visit-parents@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz#4d5f85755c3b8f0dc69e21eca5d6d82d22162815" + integrity sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw== + dependencies: + "@types/unist" "^3.0.0" + unist-util-is "^6.0.0" + +unist-util-visit@^1.1.0, unist-util-visit@^1.4.0: version "1.4.1" resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-1.4.1.tgz#4724aaa8486e6ee6e26d7ff3c8685960d560b1e3" integrity sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw== @@ -19950,6 +20401,15 @@ unist-util-visit@^2.0.0: unist-util-is "^4.0.0" unist-util-visit-parents "^3.0.0" +unist-util-visit@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-5.0.0.tgz#a7de1f31f72ffd3519ea71814cccf5fd6a9217d6" + integrity sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg== + dependencies: + "@types/unist" "^3.0.0" + unist-util-is "^6.0.0" + unist-util-visit-parents "^6.0.0" + universal-user-agent@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.1.tgz#15f20f55da3c930c57bddbf1734c6654d5fd35aa" @@ -19984,9 +20444,9 @@ unpipe@1.0.0, unpipe@~1.0.0: integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== unplugin@^1.3.1: - version "1.8.0" - resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-1.8.0.tgz#08540733c6e2f2fe343735816d1f622b4d083dd1" - integrity sha512-yGEQsodWICmgt7asHF7QzqDZYeEP9h14vyd9Lul98UnYf29pLZZLwI09z2QdTjwU/FCkum1SRvsK7cx232X8NA== + version "1.10.1" + resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-1.10.1.tgz#8ceda065dc71bc67d923dea0920f05c67f2cd68c" + integrity sha512-d6Mhq8RJeGA8UfKCu54Um4lFA0eSaRa3XxdAJg8tIdxbu1ubW0hBCZUL7yI2uGyYCRndvbK8FLHzqy2XKfeMsg== dependencies: acorn "^8.11.3" chokidar "^3.6.0" @@ -20104,18 +20564,18 @@ url@^0.11.0: qs "^6.11.2" usb@^2.11.0: - version "2.12.0" - resolved "https://registry.yarnpkg.com/usb/-/usb-2.12.0.tgz#3c00faf6d3bf830b5a45fa510157f23df10e7d73" - integrity sha512-C/egt5PQWcBZq5jABOpBCbhZrB2ftyXdx+cEnK7qowo0ALkfclfrQGlCMbj0VbirfIGayvmWMYQ8Dnii5A4pXQ== + version "2.12.1" + resolved "https://registry.yarnpkg.com/usb/-/usb-2.12.1.tgz#f7a68ddb1314d56758e3e3b1265bc467922a9503" + integrity sha512-hgtoSQUFuMXVJBApelpUTiX7ZB83MQCbYeHTBsHftA2JG7YZ76ycwIgKQhkhKqVY76C8K6xJscHpF7Ep0eG3pQ== dependencies: "@types/w3c-web-usb" "^1.0.6" node-addon-api "^7.0.0" node-gyp-build "^4.5.0" use-callback-ref@^1.2.3, use-callback-ref@^1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.1.tgz#9be64c3902cbd72b07fe55e56408ae3a26036fd0" - integrity sha512-Lg4Vx1XZQauB42Hw3kK7JM6yjVjgFmFC5/Ab797s79aARomD2nEErc4mCgM8EZrARLmmbWpi5DGCadmK50DcAQ== + version "1.3.2" + resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.2.tgz#6134c7f6ff76e2be0b56c809b17a650c942b1693" + integrity sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA== dependencies: tslib "^2.0.0" @@ -20302,7 +20762,7 @@ vfile-location@^2.0.0: resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-2.0.6.tgz#8a274f39411b8719ea5728802e10d9e0dff1519e" integrity sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA== -vfile-message@*: +vfile-message@*, vfile-message@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-4.0.2.tgz#c883c9f677c72c166362fd635f21fc165a7d1181" integrity sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw== @@ -20325,16 +20785,6 @@ vfile-message@^2.0.0: "@types/unist" "^2.0.0" unist-util-stringify-position "^2.0.0" -vfile@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/vfile/-/vfile-2.3.0.tgz#e62d8e72b20e83c324bc6c67278ee272488bf84a" - integrity sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w== - dependencies: - is-buffer "^1.1.4" - replace-ext "1.0.0" - unist-util-stringify-position "^1.0.0" - vfile-message "^1.0.0" - vfile@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/vfile/-/vfile-3.0.1.tgz#47331d2abe3282424f4a4bb6acd20a44c4121803" @@ -20355,6 +20805,15 @@ vfile@^4.0.0: unist-util-stringify-position "^2.0.0" vfile-message "^2.0.0" +vfile@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-6.0.1.tgz#1e8327f41eac91947d4fe9d237a2dd9209762536" + integrity sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw== + dependencies: + "@types/unist" "^3.0.0" + unist-util-stringify-position "^4.0.0" + vfile-message "^4.0.0" + vite-node@1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.2.2.tgz#f6d329b06f9032130ae6eac1dc773f3663903c25" @@ -20378,13 +20837,13 @@ vite@5.0.5: fsevents "~2.3.3" vite@^5.0, vite@^5.0.0: - version "5.1.4" - resolved "https://registry.yarnpkg.com/vite/-/vite-5.1.4.tgz#14e9d3e7a6e488f36284ef13cebe149f060bcfb6" - integrity sha512-n+MPqzq+d9nMVTKyewqw6kSt+R3CkvF9QAKY8obiQn8g1fwTscKxyfaYnC632HtBXAQGc1Yjomphwn1dtwGAHg== + version "5.2.10" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.2.10.tgz#2ac927c91e99d51b376a5c73c0e4b059705f5bd7" + integrity sha512-PAzgUZbP7msvQvqdSD+ErD5qGnSFiGOoWmV5yAKUEI0kdhjbH6nMWVyZQC/hSc4aXwc0oJ9aEdIiF9Oje0JFCw== dependencies: - esbuild "^0.19.3" - postcss "^8.4.35" - rollup "^4.2.0" + esbuild "^0.20.1" + postcss "^8.4.38" + rollup "^4.13.0" optionalDependencies: fsevents "~2.3.3" @@ -20536,9 +20995,9 @@ watchpack@^1.7.4: watchpack-chokidar2 "^2.0.1" watchpack@^2.2.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" - integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== + version "2.4.1" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.1.tgz#29308f2cac150fa8e4c92f90e0ec954a9fed7fff" + integrity sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg== dependencies: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" @@ -20808,30 +21267,30 @@ which-builtin-type@^1.1.3: which-typed-array "^1.1.9" which-collection@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" - integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0" + integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== dependencies: - is-map "^2.0.1" - is-set "^2.0.1" - is-weakmap "^2.0.1" - is-weakset "^2.0.1" + is-map "^2.0.3" + is-set "^2.0.3" + is-weakmap "^2.0.2" + is-weakset "^2.0.3" which-module@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== -which-typed-array@^1.1.13, which-typed-array@^1.1.14, which-typed-array@^1.1.2, which-typed-array@^1.1.9: - version "1.1.14" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.14.tgz#1f78a111aee1e131ca66164d8bdc3ab062c95a06" - integrity sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg== +which-typed-array@^1.1.13, which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.2, which-typed-array@^1.1.9: + version "1.1.15" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" + integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== dependencies: - available-typed-arrays "^1.0.6" - call-bind "^1.0.5" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" for-each "^0.3.3" gopd "^1.0.1" - has-tostringtag "^1.0.1" + has-tostringtag "^1.0.2" which@^1.2.14, which@^1.2.9, which@^1.3.1: version "1.3.1" @@ -20919,14 +21378,6 @@ worker-plugin@^5.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-3.0.1.tgz#288a04d87eda5c286e060dfe8f135ce8d007f8ba" - integrity sha512-iXR3tDXpbnTpzjKSylUJRkLuOrEC7hwEB221cgn6wtF8wpmz28puFXAEfPT5zrjM3wahygB//VuWEr1vTkDcNQ== - dependencies: - string-width "^2.1.1" - strip-ansi "^4.0.0" - wrap-ansi@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" @@ -21217,3 +21668,8 @@ yup@1.3.3: tiny-case "^1.0.3" toposort "^2.0.2" type-fest "^2.19.0" + +zwitch@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.4.tgz#c827d4b0acb76fc3e685a4c6ec2902d51070e9d7" + integrity sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==